PHP curl_exec возвращает как HTTP / 1.1 100 Continue, так и HTTP / 1.1 200 OK, разделенные пробелом

Я вызываю службу из PHP с помощью cURL, например:

$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. Укажите, что завиток не должен ожидать 100-continue ? (Как?)
  2. Укажите, что завиток должен отправлять только заголовки последнего ответа? (Как?)
  3. Вручную проверьте 100 Continue заголовков 100 Continue и проигнорируйте их и их следующую пустую строку? (В этом случае, есть ли другие подобные вещи, которые могут произойти, что я должен проверить вручную?)

Если я не пропущу что-то очевидное, я уверен, что люди наткнулись на это и решили его много раз!

Solutions Collecting From Web of "PHP curl_exec возвращает как HTTP / 1.1 100 Continue, так и HTTP / 1.1 200 OK, разделенные пробелом"

Я выберу # 1. Вы можете заставить curl отправить пустой заголовок «Expect», добавив:

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

к вашему коду

Если вы хотите проверить его вручную, вы должны определить свой собственный обратный вызов заголовка и, возможно, написать обратный вызов (посмотрите CURLOPT_HEADERFUNCTION и CURLOPT_WRITEFUNCTION в файле curl_setopt ), который просто игнорирует все заголовки «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=="; 

Я проверил это, и это приводит к следующему результату:

  == Отправленные заголовки ==
 POST /curl_test.php HTTP / 1.1
 Хост: тест
 Принять: * / *
 Контент-длина: 242
 Ожидайте: 100-продолжить
 Content-Type: multipart / form-data;  граница = ----------------------------
 d86ac263ce1b

 == Конец отправленных заголовков ==

 == Ответы заголовков ==
 HTTP / 1.1 100 Продолжить

 HTTP / 1.1 200 OK
 Дата: Пт, 06 Июл 2012 14:21:53 GMT
 Сервер: Apache / 2.4.2 (Win32) PHP / 5.4.4
 X-Powered-By: PHP / 5.4.4
 Контент-длина: 112
 Content-Type: text / plain

 == Конечные ответы ==

 == Тело ответа ==
 ** ФОРМА ДАННЫХ **
 array (2) {
   [ "Поле1"] =>
   строка (3) "foo"
   [ "Поле2"] =>
   строка (3) "bar"
 }
 ** ДАННЫЕ КОНЕЧНОЙ ФОРМЫ **
 == Конец тела == 

Я столкнулся с этим с 100 и 302 и т. Д. Это раздражает, но иногда необходимо (вызовы gdata и т. Д.), Поэтому я бы сказал, что оставить завиток, возвращая все заголовки и немного вытягивая тело.

Я обрабатываю это так (не могу найти мой фактический код, но вы получите идею):

 $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); 

Я жалуюсь на долгоживущий хакерский метод (предпочтет, чтобы он скручивался каким-то образом), но с годами он работал хорошо. сообщите нам, как вы поживаете.

у меня была та же проблема, но это решение действительно замечает работу для меня, окончательно я нашел этот метод и все его прекрасное:

мы должны подготовить поля данных перед отправкой:

 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-поле сообщения с нормальными данными: (name1 = val1, name2 = val2, …) 2- почтовое поле с файловыми данными: (name_file 1, path_file1, name_file2 = path_file2, ..)

и окончательно вызовите эту функцию, прежде чем выполнять завиток, подобный этому. $ r = curl_custom_postfields ($ curl, $ post, $ postfields_files);