Fedex Ship API返回压缩错误响应的相关技术咨询
背景
我已基于Check Rates API实现Fedex API,并可通过Ship API创建面单。沙箱环境测试正常后完成面单认证并上线,该API本应返回JSON格式数据,但在生产与沙箱环境中,通过cURL调用Ship API时偶尔会收到非JSON的压缩响应,而OAuth及Check Rates API调用从未出现此类问题。
这类压缩响应通常对应请求体的错误,例如将packagingType设为FEDEX_PAK但包裹重量超过20磅、尺寸单位使用CM而非IN等。此前在沙箱环境中曾收到JSON格式的错误响应并完成了解析逻辑,当时以为压缩响应是沙箱已知问题,现在发现生产环境也存在该情况。
联系Fedex客服的效果参差不齐:第一位客服能查看API调用记录,明确告知错误原因与解决方案,还能实时查看修复后的正常响应;但后续多次联系均未得到有效帮助,最后一位客服称压缩响应由我的代码导致,让我自行处理。
我的cURL请求代码
function fedexRequest($endpoint, $post, $header = null) { //$ch = curl_init('https://apis-sandbox.fedex.com/' . $endpoint); // sandbox $ch = curl_init('https://apis.fedex.com/' . $endpoint); // live curl_setopt_array($ch, [ CURLOPT_SSL_VERIFYPEER => true, CURLOPT_SSL_VERIFYHOST => 2, CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_POSTFIELDS => $post, ]); if ($header) curl_setopt($ch, CURLOPT_HTTPHEADER, $header); return curl_exec($ch); }
技术问题
- 这类压缩响应是否由我的cURL请求配置导致?
- 设置
CURLOPT_ENCODING能否更妥善地处理此类响应? - 若收到压缩响应,使用
gzread还是ZipArchive解压以获取实际错误码更合适?
1. 压缩响应是否由cURL配置导致?
不是你的cURL配置直接导致的。Fedex的Ship API在处理错误请求时,可能会主动返回gzip压缩的响应,而你的请求没有声明支持压缩(未发送Accept-Encoding头),但Fedex依然返回了压缩数据——这更像是Fedex API的行为不一致问题,毕竟OAuth和Check Rates API没有这个情况。你的cURL代码只是没有处理这种异常的压缩响应,并非触发它的原因。
2. 设置CURLOPT_ENCODING能否解决?
绝对可以。设置CURLOPT_ENCODING => ''会让cURL自动添加Accept-Encoding: gzip, deflate请求头,同时自动处理响应的解压。这样不管Fedex返回的是JSON还是压缩后的错误响应,cURL都会帮你解压成明文,你直接拿到的就是可解析的内容(大概率是JSON格式的错误信息)。修改后的代码片段如下:
curl_setopt_array($ch, [ CURLOPT_SSL_VERIFYPEER => true, CURLOPT_SSL_VERIFYHOST => 2, CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_POSTFIELDS => $post, CURLOPT_ENCODING => '' // 添加这一行 ]);
3. gzread还是ZipArchive?
如果没有设置CURLOPT_ENCODING手动处理的话,优先用gzread。因为Fedex返回的压缩响应几乎都是gzip格式(HTTP压缩最常用的格式),而ZipArchive是处理ZIP文件的,不适合处理gzip流。手动处理的示例代码:
$response = curl_exec($ch); $encoding = curl_getinfo($ch, CURLINFO_CONTENT_ENCODING); if ($encoding === 'gzip' && !empty($response)) { $gzip = gzopen('data://text/plain;base64,' . base64_encode($response), 'rb'); $response = gzread($gzip, 1000000); gzclose($gzip); } // 之后再尝试解析JSON
不过更推荐直接用CURLOPT_ENCODING让cURL自动处理,避免手动解压的额外代码和潜在问题。
内容的提问来源于stack exchange,提问作者Mike Volmar

