使用PHP cURL发送JSON POST请求

5
我有以下PHP代码:
curl_setopt($ch, CURLOPT_URL, $URL);
curl_setopt($ch, CURLOPT_USERAGENT, $this->_agent);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_AUTOREFERER, true);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $this->_headers);
curl_setopt($ch, CURLOPT_ENCODING , "gzip");
curl_setopt($ch, CURLOPT_VERBOSE, false); 
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_TIMEOUT,  120);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_COOKIEFILE, $this->_cookie_file_path);
curl_setopt($ch, CURLOPT_COOKIEJAR, $this->_cookie_file_path);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{"folderId":"1","parameters":{"amount":3,"ascending":false,"offset":0,"sort":"date"}}');
curl_setopt($ch, CURLOPT_POST, 1); 

但我不明白为什么它不起作用。我要将JSON发送到的API说参数未被接收。我的代码有问题吗?我认为整个问题在于JSON参数......我不确定该如何发送它们,因为在简单表单中通常不会出现任何“name->value”对,只有没有任何名称的JSON代码。

发送的 Content-Type 是什么?为什么不使用 json_encode - mario
@mario 我尝试使用 curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/json'));,但仍然无法正常工作。默认情况下,我的标头设置为 $headers = array("Expect:"); 我不知道它如何与 json_encode 协同工作。 - Ameli
你需要咨询API维护者,我们只能猜测。 - mario
@mario 我在这个链接上添加了调试信息(firebug),因为我无法在SO上发布它。它说它格式不正确(尽管我尝试了几次“格式化”)。http://pastebin.com/Ujdim8t8 - Ameli
如果你有使用这个接口并且实际工作的东西,那么请使用代理并记录它:p 然后找出你的脚本做了什么不同之处,并排除所有差异(fiddler代理非常适合此类操作,它甚至支持伪造证书/MITM攻击以便窥探HTTPS加密连接、解码gzip/deflate等)。 - hanshenrik
10个回答

5
您可以尝试以下步骤。如果我们有一个数据数组,那么应该使用php的json_encode进行JSON编码。您还应该在header中添加content-type,可以在curl中定义为curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
$data = array("country"=>"US","states"=>array("MHASASAS"=>"MH","XYZABABA"=>"XYZ"));
$postdata = json_encode($data);

$ch = curl_init($URL);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
$result = curl_exec($ch);
curl_close($ch);

如果您能在代码块中添加一些注释,我们将不胜感激。 - mrun
基本上,如果我们有一个数据数组,那么应该使用PHP的json_encode进行JSON编码。但是这里不是这样的情况,它们有一个包含有效JSON的字符串字面量。 - Quentin
在2011年的问题评论中,他们说他们已经这样做了,“而且你还应该添加内容类型”。 - Quentin

3
你可以使用这个并将其替换为
curl_setopt($ch, CURLOPT_POSTFIELDS, '{"folderId":"1","parameters":{"amount":3,"ascending":false,"offset":0,"sort":"date"}}');

使用这个

$Parameters = array(
    'MerchantCode'        => $MerchantCode,
    'PriceValue'          => $amount,
    'ReturnUrl'           => $callback,
    'InvoiceNumber'       => $resnum,
);

    curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($Parameters));

2

如果您使用POST方法,请注意以下内容:

CURLOPT_POST 设置为TRUE以执行常规的HTTP POST操作。这种POST是正常的application/x-www-form-urlencoded类型,最常用于HTML表单。

@see http://php.net/manual/en/function.curl-setopt.php

因此,您可以按照以下方式进行操作:

$ar_form = array('name'=>'PHPJungle','age'=>66,'gender'=>'male');
$poststr = http_build_query($ar_form ); # important

$options[CURLOPT_HTTPGET] = false;
$options[CURLOPT_POST] = true;
$options[CURLOPT_POSTFIELDS] = $poststr ; //default type:application/x-www-from-urlencoded

curl_setopt_array ( $ch, $options );
# @todo your other codes

这是我长期使用的类,基于PHP cURL实现。它支持GET/POST方法,同时支持HTTP/HTTPS协议。

@see https://github.com/phpjungle/iHttp/


我通常使用 Fiddler 来捕获 HTTP 请求。下载链接:http://www.telerik.com/fiddler。它是一个很棒的工具,支持代理等功能。 - PHPJungle

2
您可以使用curl发送JSON数据,方法如下:
在命令提示符中:
    curl -X POST -H "Content-Type: application/json" -d '{"folderId":"1","parameters":{"amount":3,"ascending":false,"offset":0,"sort":"date"}}' $url

使用PHP:
    $data = array("folderId"=>"1","parameters"=>array("amount"=>3,"ascending"=>false,"offset"=>0,"sort"=>"date"));
    $postdata = json_encode($data);
    OR
    $postdata = '{"folderId":"1","parameters":{"amount":3,"ascending":false,"offset":0,"sort":"date"}}';
    
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
    $result = curl_exec($ch);
    curl_close($ch);

    print_r($result);

1
$link = "http://test.domain/myquery";
   $json = '{"folderId":"1","parameters":{"amount":3,"ascending":false,"offset":0,"sort":"date"}}';
   $postdata = json_decode($json);
 echo openurl($link, $postdata);

这个函数作用是将 JSON 字符串转换为数组。
function openurl($url, $postvars = "") {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postvars);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, '3');
        $content = trim(curl_exec($ch));
        curl_close($ch);
        return $content;
    }

1

您尚未设置内容类型,因此帖子数据将作为表单数据发送。请尝试将内容类型设置为application/json。

如果这样不起作用,请尝试使用数组包装json字符串。


我添加了curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/json'));,但仍然无法工作。 - Ameli
尝试使用array('jsoncode')作为POST字段。如果这不起作用,您将需要提供请求头或者面临盲猜测的局面。 - Anthony
请查看调试信息(firebug)http://pastebin.com/Ujdim8t8 由于我无法在SO上发布它,因此我在此链接中添加了调试信息(firebug)。它说格式不正确(尽管我尝试了几次“格式化”)。 - Ameli
1
如果您正在从PHP提交它,您不应该能够从Firebug中看到HTTP请求/响应。请尝试以下操作:1)将此添加到您的curlopt中 - curl_setopt($ch, CURLINFO_HEADER_OUT, true); 2)在curl_exec之后,输出您发送的请求标头:var_dump(curl_getinfo($ch,CURLINFO_HEADER_OUT));一旦我们可以看到您实际请求的内容,就应该更容易确定为什么会出现错误。 - Anthony
我添加了来自Firebug的HTTP请求/响应,以便精确了解其工作方式。我的意思是我需要在PHP中模拟它。 - Ameli
我在这个链接http://pastebin.com/Vrv01HBj中添加了来自php-curl的日志。我还打印json代码,这样你就可以在日志开头看到它。 - Ameli

1

如果您的API端点使用请求主体发送JSON数据,您可以使用Guzzle。文档在这里doc

use GuzzleHttp\Client;
$client = new Client();
$request = $this->client->post($url,array(
            'content-type' => 'application/json'
    ),array());
$request->setBody($json_data);
$response = $request->send();
return $response;

希望这个工作。

1
你可以通过以下步骤完成它:

$data = array(
    'folderId'=>"1","parameters"=>array(
        "amount"=>"3","ascending"=>false,"offset"=>0,"sort"=>"date"
    )
);

$data_string = http_build_query($data);

$ch = curl_init();
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_POST, count($data));
curl_setopt($ch,CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ch);
curl_close($ch);

$result = json_decode($result,true);

我不知道你是否需要头信息。默认情况下,它已经是application/x-www-form-urlencode

如果不起作用,请尝试更改数组中的$data值。希望能有所帮助。:)


使用 http_build_query 在 CURLOPT_POSTFIELDS 中解决了我的问题。 - Ben in CA

0

我不确定这是否是解决方案,但当我发布JSON时,这对我有效,将JSON更改为

'{"folderId":"1","parameters":{"amount":3,"ascending":false,"offset":0,"sort":"date"}}'

"{'folderId':'1','parameters':{'amount':3,'ascending':false,'offset':0,'sort':'date'}}"

我所做的唯一更改是现在双引号在外面,这对我有效,但显然我正在发布到不同的服务器

我能提供的唯一其他帮助是下载网络调试工具,例如FiddlerCharles代理,并监视发送/接收的请求,可能是您的代码中还有其他问题。

希望我有所帮助 :)


我唯一的修改是将双引号放在外面,然而现在JSON是无效的。 - Quentin

0

首先,请检查Curl的HTTP状态码

$http_code= curl_get_info($exec_res,CURL_HTTP_CODE);

然后修改此请求头设置为post header API服务器,添加一个记录器以记录这些请求信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接