簡體   English   中英

PHP curl_exec返回HTTP / 1.1 100 Continue和HTTP / 1.1 200 OK,以空格分隔

[英]PHP curl_exec returns both HTTP/1.1 100 Continue and HTTP/1.1 200 OK separated by space

我正在使用cURL從PHP調用服務,如下所示:

$response = curl_exec($ch);

並且請求/響應標頭看起來像這樣:

請求:

POST /item/save HTTP/1.1
Host: services.mydomain.com
Accept: */*
Content-Length: 429
Expect: 100-continue
Content-Type: multipart/form-data

響應:

HTTP/1.1 100 Continue

HTTP/1.1 200 OK
Date: Fri, 06 Jul 2012 08:37:01 GMT
Server: Apache
Vary: Accept-Encoding,User-Agent
Content-Length: 256
Content-Type: application/json; charset=utf-8

其次是身體(json編碼數據)。

問題是常見的事情是在遇到第一個空行的情況下在響應中拆分標題和正文,除非在這種情況下,空行在100 Continue ,因此其他所有內容都被推入正文 - 這不是有效的json了:-)

所以我的問題是:解決這個問題的常用方法是什么? 我有3個選項排成一行:

  1. 指定curl不應該期望100-continue (怎么樣?)
  2. 指定curl應該只發回最后一個響應的標題? (怎么樣?)
  3. 手動檢查100 Continue標題並忽略它們及其后面的空行? (在這種情況下,還有其他可能發生的類似事情,我應該手動檢查嗎?)

除非我遺漏了一些明顯的東西,否則我確信人們偶然發現了這個問題並多次解決了!

我會選擇#1。 您可以通過添加以下命令強制curl發送空的“Expect”標題:

curl_setopt($ch, CURLOPT_HTTPHEADER,array("Expect:"));

你的代碼

如果你想手動檢查它,你應該定義自己的頭回調,也可以寫回調(在curl_setopt doc中查找CURLOPT_HEADERFUNCTION和CURLOPT_WRITEFUNCTION),它只是忽略所有“HTTP / 1.1 100 Continue”標題。

這是另一種使用我在評論中描述的方法的方法,它使用CURLINFO_HEADER_SIZE將響應解析為標題與正文:

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://test/curl_test.php");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLINFO_HEADER_OUT, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
// sets multipart/form-data content-type
curl_setopt($ch, CURLOPT_POSTFIELDS, array(
  'field1' => 'foo',
  'field2' => 'bar'
));

$data = curl_exec($ch);

// if you want the headers sent by CURL
$sentHeaders = curl_getinfo($ch, CURLINFO_HEADER_OUT);
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
curl_close($ch);

$header = substr($data, 0, $headerSize);
$body = substr($data, $headerSize);
echo "==Sent Headers==\n$sentHeaders\n==End Sent Headers==\n";
echo "==Response Headers==\n$headers\n==End Response Headers==\n";
echo "==Response Body==\n$body\n==End Body==";

我已對此進行了測試,結果如下:

==Sent Headers==
POST /curl_test.php HTTP/1.1
Host: test
Accept: */*
Content-Length: 242
Expect: 100-continue
Content-Type: multipart/form-data; boundary=----------------------------
d86ac263ce1b

==End Sent Headers==

==Response Headers==
HTTP/1.1 100 Continue

HTTP/1.1 200 OK
Date: Fri, 06 Jul 2012 14:21:53 GMT
Server: Apache/2.4.2 (Win32) PHP/5.4.4
X-Powered-By: PHP/5.4.4
Content-Length: 112
Content-Type: text/plain

==End Response Headers==

==Response Body==
**FORM DATA**
array(2) {
  ["field1"]=>
  string(3) "foo"
  ["field2"]=>
  string(3) "bar"
}
**END FORM DATA**
==End Body==

我已經遇到了100s和302s等這很討厭,但有時需要(gdata調用等)所以我會說讓curl返回所有標題並提取身體有點不同。

我像這樣處理它(找不到我的實際代碼,但你會得到這個想法):

$response = curl_exec($ch);

$headers = array();
$body = array();

foreach(explode("\n\n", $response) as $frag){
  if(preg_match('/^HTTP\/[0-9\.]+ [0-9]+/', $frag)){
    $headers[] = $frag;
  }else{
    $body[] = $frag;
  }
}

echo implode("\n\n", $headers);
echo implode("\n\n", $body);

我不喜歡這種長篇大論的hackish方法(如果卷曲以某種方式標記身體內容,我會更喜歡它)但多年來它一直運作良好。 讓我們知道您的身體情況如何。

我有同樣的問題,但這個解決方案確實為我工作,最終我找到了這個方法,並且很好:

我們必須在發送之前准備數據發布字段:

function curl_custom_postfields($curl, array $assoc = array(), array $files = array()) {
/**
* For safe multipart POST request for PHP5.3 ~ PHP 5.4.
* @param resource $ch cURL resource
* @param array $assoc "name => value"
* @param array $files "name => path"
* @return bool
*/
// invalid characters for "name" and "filename"
static $disallow = array("\0", "\"", "\r", "\n");
// build normal parameters
foreach ($assoc as $key => $value) {
    $key = str_replace($disallow, "_", $key);
    $body[] = implode("\r\n", array(
        "Content-Disposition: form-data; name=\"{$key}\"",
        "",
        filter_var($value), 
    ));
}
// build file parameters
foreach ($files as $key => $value) {
    switch (true) {
        case false === $value = realpath(filter_var($value)):
        case !is_file($value):
        case !is_readable($value):
            continue; // or return false, throw new InvalidArgumentException
    }
    $data = file_get_contents($value);
    $value = call_user_func("end", explode(DIRECTORY_SEPARATOR, $value));
    $key = str_replace($disallow, "_", $key);
    $value = str_replace($disallow, "_", $value);
    $body[] = implode("\r\n", array(
        "Content-Disposition: form-data; name=\"{$key}\"; filename=\"{$value}\"",
        "Content-Type: application/octet-stream",
        "",
        $data, 
    ));
}

// generate safe boundary 
do {
    $boundary = "---------------------" . md5(mt_rand() . microtime());
} while (preg_grep("/{$boundary}/", $body));

// add boundary for each parameters
array_walk($body, function (&$part) use ($boundary) {
    $part = "--{$boundary}\r\n{$part}";
});

// add final boundary
$body[] = "--{$boundary}--";
$body[] = "";

// set options
return @curl_setopt_array($curl, array(
    CURLOPT_POST       => true,
    CURLOPT_POSTFIELDS => implode("\r\n", $body),
    CURLOPT_HTTPHEADER => array(
        "Expect: 100-continue",
        "Content-Type: multipart/form-data; boundary={$boundary}", // change Content-Type
    ),
));}

你必須准備兩個數組:1- post field with normal data:(name1 = val1,name2 = val2,...)2- post field with file data:(name_file 1,path_file1,name_file2 = path_file2,..)

最后在執行curl之前調用此函數。 $ r = curl_custom_postfields($ curl,$ post,$ postfields_files);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM