PHP中CURL PUT请求无法发送JSON数据的问题排查
PHP CURL PUT请求JSON数据无法发送的问题
问题场景
使用PHP的CURL构建PUT请求时,JSON数据始终无法发送到API服务器,通过Fiddler抓包发现请求体为空,服务器返回408 Request body incomplete错误。
相关代码
sendRequest函数实现
public function sendRequest($endpoint, $method, $params = [], $data = null) { $curl = curl_init(); $url = $this->host . "/" . $endpoint . "?" . http_build_query($params); $data = array( 'ItemCode' => '3505180', 'SearchCode' => '123456', ); $data_string = json_encode($data); switch ($method) { case "GET": curl_setopt($curl, CURLOPT_HTTPGET, 1); break; case "POST": curl_setopt($curl, CURLOPT_POST, 1); if ($data) { curl_setopt($curl, CURLOPT_POSTFIELDS, $data); } break; case "PUT": curl_setopt($curl, CURLOPT_PUT, 1); if ($data) { curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string); } break; default: break; } curl_setopt($curl, CURLOPT_PROXY, '127.0.0.1:51290'); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_HTTPHEADER, array( 'X-ApiKey: ' . $this->apiKey, 'administration: ' . $this->administration, 'Content-Type: application/json' )); $result = curl_exec($curl); if(curl_errno($curl)) { $result = 'Curl error: ' . curl_error($curl); } curl_close($curl); return $result; }
函数调用代码
public function updateItem($item) { $this->sendRequest("api/Item", "PUT", [], "some json data should go here"); }
抓包及错误信息
原始请求数据
PUT http://appsrv:889/api/Item HTTP/1.1 Host: appsrv:889 Accept: */* Proxy-Connection: Keep-Alive X-ApiKey: xxxxx administration: 002 Content-Type: application/json Content-Length: 44 Expect: 100-continue
服务器返回错误
HTTP/1.1 408 Request body incomplete Date: Wed, 17 Aug 2022 07:18:01 GMT Content-Type: text/html; charset=UTF-8 Connection: close Cache-Control: no-cache, must-revalidate Timestamp: 09:18:01.979 The request body did not contain the specified number of bytes. Got 0, expected 44
问题原因及解决方案
核心原因
- CURLOPT_PUT与CURLOPT_POSTFIELDS冲突:当设置
CURLOPT_PUT为1时,CURL默认期望从文件读取请求体内容,此时使用CURLOPT_POSTFIELDS无法正确传递内存中的JSON数据,导致实际请求体为空。 - 参数覆盖问题:
sendRequest函数开头直接硬编码覆盖了传入的$data参数,导致调用时传入的JSON字符串完全失效,即使硬编码的数组被转成JSON,也会因CURL配置错误无法发送。
修复步骤
步骤1:修正PUT请求的CURL配置
移除CURLOPT_PUT设置,改用CURLOPT_CUSTOMREQUEST指定PUT方法,同时保留CURLOPT_POSTFIELDS传递JSON数据:
case "PUT": curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT"); if ($data) { curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string); } break;
步骤2:保留传入的$data参数
删除函数开头硬编码覆盖$data的代码,根据传入参数的类型处理JSON转换:
// 移除硬编码覆盖的代码 // $data = array( // 'ItemCode' => '3505180', // 'SearchCode' => '123456', // ); // 改为动态处理传入的$data $data_string = ''; if ($data) { $data_string = is_array($data) ? json_encode($data) : $data; }
步骤3:确保Content-Length正确(可选)
虽然CURL会自动计算Content-Length,但针对代理或特殊服务器场景,可以手动设置:
$headers = array( 'X-ApiKey: ' . $this->apiKey, 'administration: ' . $this->administration, 'Content-Type: application/json' ); if (!empty($data_string)) { $headers[] = 'Content-Length: ' . strlen($data_string); } curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
修复后的完整sendRequest函数
public function sendRequest($endpoint, $method, $params = [], $data = null) { $curl = curl_init(); $url = $this->host . "/" . $endpoint . "?" . http_build_query($params); $data_string = ''; if ($data) { $data_string = is_array($data) ? json_encode($data) : $data; } switch ($method) { case "GET": curl_setopt($curl, CURLOPT_HTTPGET, 1); break; case "POST": curl_setopt($curl, CURLOPT_POST, 1); if ($data) { curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string); } break; case "PUT": curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT"); if ($data) { curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string); } break; default: break; } curl_setopt($curl, CURLOPT_PROXY, '127.0.0.1:51290'); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); $headers = array( 'X-ApiKey: ' . $this->apiKey, 'administration: ' . $this->administration, 'Content-Type: application/json' ); if (!empty($data_string)) { $headers[] = 'Content-Length: ' . strlen($data_string); } curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); $result = curl_exec($curl); if(curl_errno($curl)) { $result = 'Curl error: ' . curl_error($curl); } curl_close($curl); return $result; }
修正后的调用方式
public function updateItem($item) { // 可传入数组或JSON字符串 $updateData = array( 'ItemCode' => '3505180', 'SearchCode' => '123456' ); $this->sendRequest("api/Item", "PUT", [], $updateData); }
内容的提问来源于stack exchange,提问作者RickDB
相关产品推荐
相关产品推荐

