You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Laravel HTTP客户端的ResponseMiddleware中关联请求与响应?

Laravel HTTP客户端自定义日志:关联请求与响应日志

需求背景

已通过Laravel HTTP客户端的withRequestMiddleware实现每次API调用(含重试)的请求日志记录,请求携带唯一X-RequestId标识实现分组日志。现在需要在withResponseMiddleware中获取对应的requestId和attempt,将响应信息与请求日志关联更新。

解决方案

核心思路是在请求中间件中将identifier和attempt存入请求的自定义属性,后续在响应中间件中通过响应对象获取关联的请求实例,进而取出这些属性完成日志更新。

步骤1:修改请求中间件,存储关键标识到请求属性

在请求中间件中,除插入请求日志外,额外将identifier和attempt存入请求的自定义属性:

$httpClient = Http::withBasicAuth($this->apiKey, $this->apiSecret)
    ->retry(3, 100, null, false)
    ->withRequestMiddleware(function (RequestInterface $request) {
        $identifier = $request->getHeaderLine('X-RequestId'); 
        $attempt = $request->getAttribute('retry_attempts', 1);

        // 存入请求自定义属性,供响应中间件调用
        $request->setAttribute('log_identifier', $identifier);
        $request->setAttribute('log_attempt', $attempt);

        $authMethod = $request->getHeaderLine('Authorization') ?? null;
        $authMethod = is_string($authMethod) ? preg_replace("/\s*(\w+)\s+.*/", "$1", $authMethod) : null;

        DB::table('api_call_log')->insert([
            'identifier' => $identifier,
            'attempt' => $attempt,
            'method' => $request->getMethod(),
            'url' => $request->getUri(),
            'request_auth_method' => $authMethod,
            'headers' => serialize($request->getHeaders()),
            'body' => serialize($request->getBody()),
            'request_start_unix' => now()->unix(),
        ]);

        return $request;
    })
    ->withResponseMiddleware(function (ResponseInterface $response) {
        // 从响应关联的请求实例中取出标识
        $request = $response->getRequest();
        $identifier = $request->getAttribute('log_identifier');
        $attempt = $request->getAttribute('log_attempt');

        // 更新响应日志数据
        DB::table('api_call_log')
            ->where(['identifier' => $identifier, 'attempt' => $attempt])
            ->update([
                'request_end_unix' => now()->unix(),
                'response_code' => $response->getStatusCode(),
                'response_body' => serialize($response->getBody()),
                'response_headers' => serialize($response->getHeaders()),
            ]);
    });

步骤2:请求发起逻辑(保持不变)

发起请求时仍需携带X-RequestId标识:

$requestId = Str::uuid()->toString();
$endpoint = $this->apiUrl.'/myendpoint';
$response = $this->httpClient->withHeaders(['X-RequestId' => $requestId])
    ->put($endpoint, ['name' => "Hello"]);

数据表迁移(已提供)

确保日志表结构支持请求与响应字段的存储:

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::dropIfExists('api_call_log');

        Schema::create('api_call_log', function (Blueprint $table) {
            $table->string('identifier', 32);
            $table->integer('attempt')->default(1)->unsigned();

            $table->primary(['identifier','attempt']);

            $table->string('method', 32);
            $table->string('url', 32);
            $table->string('request_auth_method', 32)->nullable();
            $table->binary('headers')->nullable();
            $table->binary('body')->nullable();
            $table->integer('request_start_unix')->unsigned();
            $table->integer('request_end_unix')->unsigned()->nullable();
            $table->smallInteger('response_code')->unsigned()->nullable();
            $table->binary('response_body')->nullable();
            $table->binary('response_headers')->nullable();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('api_call_log');
    }
};

关键说明

  • Guzzle的ResponseInterface提供getRequest()方法,可获取当前响应对应的请求实例
  • 通过setAttribute()和getAttribute()操作请求的自定义属性,安全传递上下文数据
  • 利用复合主键identifier+attempt确保每次重试请求的日志能被准确更新

内容的提问来源于stack exchange,提问作者Dimitrios Desyllas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 03:17:02