使用Guzzle HTTP Client多API请求时,json_decode返回首个请求结果问题
问题排查与解决方案
核心原因猜测
你遇到的问题大概率出自两个方向:要么是$baseApiCall->sendRequest的封装方法存在复用响应的bug,要么是Guzzle响应体的流读取逻辑没处理对——Guzzle的响应体是流式对象,调用getContents()后指针会移到流末尾,若复用流对象或未重置指针,会导致读取到旧内容。
分步解决方法
1. 先确认第二个请求的真实响应
在解析前直接打印响应内容,验证是否真的返回了第一个请求的结果:
$receiptsResponse = $baseApiCall->sendRequest('GET', $receiptsApiUrl); // 打印状态码和原始响应体,确认请求结果 var_dump($receiptsResponse->getStatusCode()); echo $receiptsResponse->getBody()->getContents(); // 重置流指针,避免后续读取为空 $receiptsResponse->getBody()->rewind();
如果打印内容确实是第一个请求的结果,直接检查$baseApiCall的sendRequest实现——大概率是这个封装方法没有正确发起新请求,而是缓存/复用了第一次的响应对象。
2. 修复Guzzle响应体读取逻辑
如果sendRequest没问题,那是流读取的问题,改用Guzzle内置的json()方法直接解析,它会自动处理流的读取和重置:
if ($receiptsResponse->getStatusCode() == 200) { // 替换手动json_decode,用内置方法直接解析JSON $receiptsData = $receiptsResponse->json(); }
如果一定要手动读取,记得每次读取前重置流指针:
$body = $receiptsResponse->getBody(); $body->rewind(); // 重置到流的开头 $receiptsData = json_decode($body->getContents(), true);
3. 检查$baseApiCall的封装逻辑
打开$baseApiCall对应的类,确认sendRequest方法每次都创建了新的HTTP请求:
- 确保没有将响应对象存在类属性中重复返回
- 确认Guzzle客户端的调用是每次都发起新请求,没有错误启用缓存中间件
- 检查是否有逻辑错误导致请求URL被覆盖或复用
4. 修复URL拼接的安全问题
顺便提醒:直接把变量拼到URL查询参数里存在注入风险,建议用参数化方式构建查询:
$receiptsApiUrl = "<api URL I am using>/purchaseReceipts"; $query = [ '$filter' => "orderNumber eq '$orderNumber'", '$expand' => "purchaseReceiptLines(\$filter=lineObjectNumber eq '$lineObjectNumber')" ]; // 若sendRequest支持传入查询参数则直接传入;原生Guzzle可这么调用: $receiptsResponse = $client->request('GET', $receiptsApiUrl, ['query' => $query]);
内容的提问来源于stack exchange,提问作者Kram_Koorbse
相关产品推荐
相关产品推荐

