记一次php curl给java提交数据失败的经历

最近由于业务需求需要对接一个对外接口(对方为java),简单来说就是需要通过post方式来给对方提交数据。但是对方一直收不到数据。简化代码如下:

$url = 'http://www.test.com';
$data = array(
  'name' => 'test',
  'age' => 123,
); 
$curl = curl_init (); // 启动一个CURL会话
curl_setopt ( $curl, CURLOPT_URL, $url ); // 要访问的地址
curl_setopt ( $curl, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt ( $curl, CURLOPT_POSTFIELDS, $data); // Post提交的数据包
$result = curl_exec ( $curl ); // 执行操作
curl_close ( $curl ); 

后来发现是由于提交数据时header头的content-type跟对方不一致所导致。

  • CURLOPT_POSTFIELDS 这个参数字段数据为一个数组时,Content-Type头将会被设置成multipart/form-data(数据格式);
  • 而这个参数字符串类似’para1=val1&para2=val2&…’时,Content-Type头将会被设置成application/x-www-form-urlencoded(表单格式),就像表单提交的一样。

对方接收的Content-Type为application/x-www-form-urlencoded(表单格式),而现在PHP curl post提交数据时Content-Type为multipart/form-data(数据格式)。这才导致对方无法通过POST来接收数据。现在只需要把代码中

curl_setopt ( $curl, CURLOPT_POSTFIELDS, $data);
//更改为
curl_setopt ( $curl, CURLOPT_POSTFIELDS, http_build_query($data));

就OK了。

在PHP中通过POST方式接收的普通数据直接用$_POST就可以获取到,而如果是二进制流数据需要用$_FILES来获取。如果接收的数据是二进制流数据(文件)还用$_POST来接收,那只获取到的是这个文件的路径名字符串。

另外通过PHP的curl要发送文件,在文件名前面加上@前缀并使用完整路径就可以了。例如:

//$data['file']就是要发送的文件

$ch = curl_init();
$data = array('name' => 'Foo', 'file' => '@/home/user/test.png');
curl_setopt($ch, CURLOPT_URL, 'http://localhost/upload.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_exec($ch);