7

cURL 経由で HTTP POST 要求を送信し、応答として json 文字列を期待する単純な PHP スクリプトを用意しました (これには 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>

洞察やアイデアはありますか?

前もって感謝します!

4

4 に答える 4

22

問題が解決しました!問題は次のとおりです。

ヘッダーの連想配列を送信しても、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本文のキーと値のペアにも適用されると思います。そのため、メッセージ本文の使用http_build_query()または文字列化に関する@drew010のコメントjson_encode()も優れたアイデアです。

非常に有益なコメントと時間と配慮をありがとうございました。結局、httpトラフィック(Wiresharkを介してキャプチャされた)を並べて比較すると、問題が明らかになりました。

ありがとう!

于 2012-06-18T21:20:16.220 に答える
10

問題は、オプションとして配列を渡していることだと思いCURLOPT_POSTFIELDSます。配列を渡すことにより、サーバーがおそらく期待しているときにPOSTリクエストを使用するように強制します。multipart/form-dataapplication/x-www-form-urlencoded

変更してみる

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

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

詳細についてはhttp_build_queryを参照してください。また、次の回答も参照してください

于 2012-06-18T17:43:46.067 に答える
1

これは私のために働いた

 $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);
于 2020-06-23T13:30:53.250 に答える
1

同じ問題があり、ヘッダーの変更を修正しました。

私のコード:

$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));
于 2019-08-28T18:11:50.023 に答える