
在使用 Guzzle 发送 HTTP 请求时,若对响应体(Stream)对象误调用 getStatusCode() 方法,会导致“Call to undefined method”错误;正确做法是始终从 ResponseInterface 实例(而非其 getBody() 返回的 Stream)获取状态码。
在使用 guzzle 发送 http 请求时,若对响应体(stream)对象误调用 `getstatuscode()` 方法,会导致“call to undefined method”错误;正确做法是始终从 `responseinterface` 实例(而非其 `getbody()` 返回的 `stream`)获取状态码。
Guzzle 的 Client::request() 方法返回的是一个实现了 Psr\Http\Message\ResponseInterface 的响应对象(如 GuzzleHttp\Psr7\Response),它提供 getStatusCode()、getReasonPhrase()、getHeaders() 和 getBody() 等方法。而 getBody() 返回的是一个 Psr\Http\Message\StreamInterface 实例(例如 GuzzleHttp\Psr7\Stream),该流对象不包含 HTTP 状态信息——因此调用 $response->getBody()->getStatusCode() 必然抛出 Call to undefined method 错误。
在你的代码中,问题出现在两个位置:
-
成功分支:
$response = $client->request(...); $response = $response->getBody(); // ❌ 覆盖了原始 Response 对象 $statusCode = $response->getStatusCode(); // ❌ Stream 没有 getStatusCode()
-
异常分支(ClientException):
Prompt Log下载从 AI 编程会话日志(Clawdbot、Claude Code、Codex)中提取对话记录。该功能用于在用户要求导出提示词历史、会话日志或 `.jsonl` 格式的会话文件时使用。
$response = $e->getResponse(); $response = $response->getBody()->getContents(); // ❌ 再次覆盖为字符串 $statusCode = $response->getStatusCode(); // ❌ 字符串更不可能有该方法
✅ 正确写法是:先提取状态码,再读取响应体内容,并避免覆盖原始响应对象。以下是修复后的完整方法:
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
public function send($user, $title, $body, $data = false, $type, $image = '')
{
$client = new Client();
$url = 'https://fcm.googleapis.com/fcm/send';
$serverKey = config('services.firebase.api_key');
$headers = [
'Content-Type' => 'application/json',
'Authorization' => 'key=' . $serverKey,
];
$fields = [
'registration_ids' => [$user['fcm_token']],
'to' => $user['fcm_token'],
'notification' => [
'title' => $title,
'body' => $body,
'sound' => 'default',
],
'priority' => 10,
'data' => $data,
'android' => ['priority' => 'high'],
];
$jsonPayload = json_encode($fields);
try {
$response = $client->request('POST', $url, [
'headers' => $headers,
'body' => $jsonPayload,
]);
$statusCode = $response->getStatusCode(); // ✅ 从 Response 对象获取
$bodyContent = $response->getBody()->getContents(); // ✅ 再读取响应体
} catch (ClientException $e) {
$response = $e->getResponse();
$statusCode = $response->getStatusCode(); // ✅ 同样从 Response 获取
$bodyContent = $response->getBody()->getContents(); // ✅ 再读取内容
}
return [
'response' => $bodyContent,
'statusCode' => $statusCode,
];
}
⚠️ 注意事项:
- 不要将 $response 变量重复赋值为 getBody() 或 getContents(),否则丢失响应元数据;
- 若需结构化解析 JSON 响应,可使用 $response->getBody()->getContents() 后 json_decode(),或直接使用 Guzzle 的 json() 辅助方法(需确保响应为合法 JSON);
- Laravel 中推荐使用 Http facade(底层封装 Guzzle)替代手动实例化 Client,更简洁且与框架生命周期集成更好;
- FCM 已逐步迁移到 FCM v1 HTTP API,建议升级至使用 OAuth2 认证的现代接口,旧版 key= 方式已标记为 legacy。
掌握 Guzzle 响应对象的分层结构(Response → Body Stream → Content String)是避免此类错误的关键。










