2012-06-18 3 views
3

У меня есть простой PHP-скрипт, который отправляет HTTP-запрос POST через cURL и ожидает ответную строку json (хотелось бы использовать существующую библиотеку, например pecl_http/HTTPRequest для этого, но не могу). Последовательный вызов вызывает ошибку 415 - Неподдерживаемый тип носителя. Я думаю, что я неправильно настраиваю cURL, но после долгих поисков я не могу понять, что я делаю неправильно. Вот код:PHP cURL POST возвращает 415 - Неподдерживаемый тип носителя

class URLRequest 
{ 
    public $url; 
    public $headers; 
    public $params; 
    public $body; 
    public $expectedFormat; 
    public $method; 

    public function URLRequest($aUrl, array $aHeaders, array $aParams, $aFormat = "json", $isPost = false, $aBody = "+") 
    { 
     $this->url = $aUrl; 
     $this->headers = $aHeaders; 
     $this->params = $aParams; 
     $this->expectedFormat = $aFormat; 
     $this->method = ($isPost ? "POST" : "GET"); 
     $this->body = $aBody; 

    } 

    public function exec() 
    { 

     $queryStr = "?"; 
     foreach($this->params as $key=>$val) 
      $queryStr .= $key . "=" . $val . "&"; 

     //trim the last '&' 
     $queryStr = rtrim($queryStr, "&"); 

     $url = $this->url . $queryStr; 

     $request = curl_init(); 
     curl_setopt($request, CURLOPT_URL, $url); 
     curl_setopt($request, CURLOPT_HEADER, 1); 
     curl_setopt($request, CURLOPT_HTTPHEADER, $this->headers); 
     curl_setopt($request, CURLOPT_RETURNTRANSFER, 1); 
     //curl_setopt($request, CURLOPT_SSL_VERIFYPEER, false); 

     if($this->method == "POST") 
     { 
      curl_setopt($request, CURLOPT_POST, 1); 
      curl_setopt($request, CURLOPT_POSTFIELDS, $this->body); 

      //this prevents an additions code 100 from getting returned 
      //found it in some forum - seems kind of hacky 
      curl_setopt($request, CURLOPT_HTTPHEADER, array("Expect:")); 
     } 

     $response = curl_exec($request); 
     curl_close($request); 

     preg_match("%(?<=HTTP/[0-9]\.[0-9])[0-9]+%", $response, $code); 

     $resp = ""; 
     if($this->expectedFormat == "json") 
     { 
      //parse response 
     } 
     elseif($this->expectedFormat == "xml") 
     { 
      //parse response 
     } 

     return $resp; 

    } 
} 


$url = "http://mydomain.com/myrestcall"; 

$query = array("arg_1" =>  "test001", 
       "arg_2" =>  "test002", 
       "arg_3" =>  "test003"); 

$headers = array( "Accept-Encoding" => "gzip", 
        "Content-Type" =>  "application/json", 
        "Accept" =>    "application/json", 
        "custom_header_1" => "test011", 
        "custom_header_2" => "test012", 
        "custom_header_3" => "test013"); 

$body = array( "body_arg_1" =>  "test021", 
       "body_arg_2" =>  array("test022", "test023"), 
       "body_arg_3" =>  "test024"); 


$request = new URLRequest($url, $headers, $query, "json", true, $body); 

$response = $request->exec(); 

... и ответ:

HTTP/1.1 415 Unsupported Media Type 
Server: Apache-Coyote/1.1 
X-Powered-By: Servlet 2.5; JBoss-5.0/JBossWeb-2.1 
Content-Type: text/html;charset=utf-8 
Content-Length: 1047 
Date: Mon, 18 Jun 2012 16:30:44 GMT 

<html><head><title>JBoss Web/2.1.3.GA - Error report</title></head><body><h1>HTTP Status 415 - </h1><p><b>type</b> Status report</p><p><b>message</b> <u></u></p><p><b>description</b> <u>The server refused this request because the request entity is in a format not supported by the requested resource for the requested method().</u></p><h3>JBoss Web/2.1.3.GA</h3></body></html> 

Любые идеи или идеи?

Заранее благодарен!

+0

Вы можете попытаться добавить заголовок 'Accept' с помощью' application/json' –

+0

Спасибо, попробовал, но не люблю :(Ваш комментарий напомнил мне, что я должен указать некоторые похожие заголовки, особенно на этом примере, поэтому thanks :) – Ian

+0

Является ли веб-сервис, который вы пытаетесь запросить публичный или частный API? Возможно, вам не хватает некоторых параметров, однако ошибка ответа очень общая, и мы не сможем помочь, если это частный API. –

ответ

10

Проблема решена! Вот вопрос:

Отправка ассоциативного массива заголовков НЕ РАБОТАЕТ с помощью cURL. Есть несколько форумов, разбросанных по этим примерам с использованием ассоциативного массива для заголовков. НЕ ДЕЛАЙТЕ ЭТО!

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

Таким образом, в целом,

НЕПРАВИЛЬНО:

$headers = array( "Accept-Encoding" => "gzip", 
        "Content-Type" =>  "application/json", 
        "custom_header_1" => "test011", 
        "custom_header_2" => "test012", 
        "custom_header_3" => "test013"); 

ПРАВО:

$headers = array( "Accept-Encoding: gzip", 
        "Content-Type: application/json", 
        "custom_header_1: test011", 
        "custom_header_2: test012", 
        "custom_header_3: test013"); 

Я надеюсь, что это пригодится в какой-то другой знатной Doofus вниз по дороге, прежде чем они тратить столько времени на отладку, сколько я.

Если бы я должен был догадаться, я бы предположил, что это же правило применяется и к парам/целям тела/значения POST, поэтому комментарий @ drew010 об использовании http_build_query() или json_encode() для строения вашего тела сообщения является отличным Идея.

Спасибо всем за ваши очень полезные комментарии, а также за вас время и внимание. В конце концов, сравнительное сравнение HTTP-трафика (захваченного через Wireshark) показало проблему.

Спасибо!

7

Я думаю, проблема в том, что вы передаете массив как CURLOPT_POSTFIELDS. Передавая массив, это вынуждает запрос POST использовать multipart/form-data, когда сервер, вероятно, ожидает application/x-www-form-urlencoded.

Попробуйте изменить

curl_setopt($request, CURLOPT_POSTFIELDS, $this->body); 

в

curl_setopt($request, CURLOPT_POSTFIELDS, http_build_query($this->body)); 

См http_build_query для получения дополнительной информации, а также этот ответ: My cURL request confuses some servers?

+0

Спасибо за предложение - тот же ответ, хотя. Однако я буду помнить об этом. Ты делаешь доброе дело. – Ian

+0

Обнаруживать весь запрос в Wireshark может быть полезно, чтобы вы могли видеть HTTP-запрос и ответ. Ожидают ли они, что вы публикуете данные JSON, а не urlencoded данные? – drew010

+0

Ожидается, что JSON, и за мой ответ на комментарий Бориса, я собираюсь последовать за вашим советом, Wireshark мой зов вместе с вызовом, отправленным с Плаката, и сравнить их. – Ian

Смежные вопросы