我尝试为 Laravel 的 http 客户端提供自定义日志机制:
$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);
$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) {
// How I can get requestId and attempt here
});
}
记录到此表:
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');
}
};
这个想法是,一旦我尝试调用请求,我会在
withRequestMiddleware
上记录尝试,完成后,我会在 withResponseMiddleware
上记录每个请求的响应,我会提供一个唯一的标识符,以便每次尝试调用 api 时都可以进行分组:
$requestId = Str::uuid()->toString();
$endpoint = $this->apiUrl.'/myendpoint';
$response = $this->httpClient->withHeaders(['X-RequestId'=>$requestId])
->put($endpoint,['name'=>"Hello"]);
这样我每次尝试调用 api 时都可以保留日志并记录尝试是否成功。
问题是我如何将必要的请求与我在
withResponseMiddleware
关闭时的响应关联起来?
还有另一个技巧可能对你的情况有帮助
首先创建一个名为
macro
的 withRequestId
,如下所示
Http::macro('withRequestId', function ($id) {
return $this->withHeaders(['X-Request-ID' => $id]);
});
之后你可以像这样到达相同的请求ID
$id = str()->uuid()->toString();
$response = Http::withRequestId($id)->get('https://google.com');
info(['request_id' => $id]);