【问题标题】:PHP cURL POST returns a 415 - Unsupported Media TypePHP cURL POST 返回 415 - 不支持的媒体类型
【发布时间】:2012-06-20 17:15:55
【问题描述】:

我有一个简单的 PHP 脚本,它通过 cURL 发送 HTTP POST 请求,并期望一个 json 字符串作为响应(我很想为此使用 pecl_http/HTTPRequest 之类的现有库,但不能)。调用始终失败并出现 415 错误 - 不支持的媒体类型。我认为我没有正确配置 cURL,但经过大量搜索,我无法找出我做错了什么。这是一些代码:

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>

有什么见解或想法吗?

提前致谢!

【问题讨论】:

  • 您可以尝试添加Accept 标头和application/json
  • 谢谢,试过了,但不喜欢 :( 你的评论提醒我,我应该在示例中特别指出一些类似的标题,所以谢谢 :)
  • 您尝试请求公共或私有 API 的 Web 服务?但是,您可能缺少一些参数,响应错误非常笼统,如果它是私有 API,我们可能无法提供帮助。
  • 私人的,不幸的是。我知道这严重限制了其他人可以帮助解决此问题的程度,但我担心他们是休息时间。大多数情况下,我希望对 php 或 curl 更有经验的人会发现我遇到的一些常见陷阱。
  • 您还有其他方法可以测试您的网络服务吗?在花很多时间调试看起来相当简单和正确的代码之前,请确保远程服务没有损坏。

标签: php post curl jboss


【解决方案1】:

我认为问题在于您将数组作为CURLOPT_POSTFIELDS 选项传递。通过传递一个数组,这会强制POST 请求在服务器可能期待application/x-www-form-urlencoded 时使用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?

【讨论】:

  • 感谢您的建议-尽管回复相同。不过,我会牢记这一点。你说得很好。
  • 在 Wireshark 中嗅探整个请求可能会有所帮助,这样您就可以看到 HTTP 请求和响应。他们是否希望您发布 JSON 数据而不是 urlencoded 数据?
  • 它期待 JSON,根据我对 Boris 评论的回复,我将关注你的委员会,Wireshark 我的电话以及来自海报的电话,并比较两者。
  • 在这种情况下,您可能需要将 CURLOPT_POSTFIELDS 设置为 json_encode($this-&gt;body) 并确认发出的内容类型标头没有被 curl 覆盖为除 application/json 以外的任何内容
  • 查看 Wireshark 对此事的看法 - 以为我知道了,并发表了此评论,然后不得不对其进行编辑以删除错误的发现...
【解决方案2】:

问题解决了!问题来了:

发送标题的关联数组不适用于 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");

我希望这对其他一些高贵的傻瓜能派上用场,以免他们像我一样浪费时间进行调试。

如果我不得不猜测,我会假设相同的规则也适用于 POST 正文键/值对,这就是为什么 @drew010 关于使用 http_build_query()json_encode() 来字符串化您的消息正文的评论也是一个好主意。

感谢大家提供非常有用的 cmets,感谢您的时间和考虑。最后,通过并排比较 http 流量(通过 Wireshark 捕获)发现了问题。

谢谢!

【讨论】:

  • 该死!我正在尝试一切,实际上发现了几十个不同的页面和教程,展示了如何使用 key=>value 设置标题,但它根本不起作用!谢谢,伊恩!
  • 感谢您节省可能数小时/数天的挫败感 :)
【解决方案3】:

我遇到了同样的问题,我修复了更改标题。

我的代码:

$authorization = 'authorization: Bearer '.trim($apiKey);
$header = [
'Content-Type: application/json',
$authorization
];
curl_setopt($session, CURLOPT_HTTPHEADER, $header);

不知道为什么数组函数不起作用:

curl_setopt($session, CURLOPT_HTTPHEADER, array('Content-Type: 
application/json',
$authorization));

【讨论】:

    【解决方案4】:

    这对我有用

     $data ="data";
    
     $headers = [
                    "Content-Type: application/json",
                    "X-Content-Type-Options:nosniff",
                    "Accept:application/json",
                    "Cache-Control:no-cache"
                ];
    
      $auth =  $USER . ":" . $PASSWORD;
    
    
     $curl = curl_init();
            curl_setopt($curl,CURLOPT_URL, $url);
            curl_setopt($curl,CURLOPT_RETURNTRANSFER, true);
            curl_setopt($curl,CURLOPT_ENCODING, "");
            curl_setopt($curl,CURLOPT_MAXREDIRS, 10);
            curl_setopt($curl,CURLOPT_TIMEOUT, 0);
            curl_setopt($curl,CURLOPT_FOLLOWLOCATION, true);
            curl_setopt($curl,CURLOPT_HTTP_VERSION,CURL_HTTP_VERSION_1_1);
            curl_setopt($curl,CURLOPT_CUSTOMREQUEST, "POST");
            curl_setopt($curl,CURLOPT_POSTFIELDS, json_encode($data)); 
            curl_setopt($curl, CURLOPT_USERPWD,  $auth);  
            curl_setopt($curl,CURLOPT_HTTPHEADER, $headers);
    
             $result = curl_exec($curl);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-11-26
      • 2016-11-21
      • 1970-01-01
      • 1970-01-01
      • 2020-09-03
      • 2017-03-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多