2012-06-18 133 views
3

我有一個簡單的PHP腳本,它通過cURL發送一個HTTP POST請求,並且期望一個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

你可以試着用'application/json'添加'Accept'頭文件 –

+0

謝謝,試過了,但沒有愛:(你的評論提醒我,我應該在例子中特別指出一些類似的頭文件,謝謝:) – Ian

+0

您試圖請求公共或私有API的web服務?您可能會缺少一些參數,但是,響應錯誤非常普遍,如果它是私有API,我們可能無法提供幫助。 –

回答

10

問題解決了!這是問題:

發送標題的關聯數組不能使用cURL。有幾個論壇分散顯示使用關聯數組作爲標題的示例。不要這樣做!

正確方式(也散落在互聯網絡,但我太密有所察覺)是構建你的頭鍵/值對字符串,並通過這些字符串時的標準陣列設置CURLOPT_HTTPHEADER選項。

因此,在總結,

WRONG:

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

RIGHT:

$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選項。通過傳遞數組,當服務器可能期望application/x-www-form-urlencoded時,這會強制POST請求使用multipart/form-data

嘗試改變

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

相關問題