laravel7开始加入了httpclient包,比guzzle库好用,如果是低于laravel7可以把Httpclient包手动引入到项目中
这里对httpclient做一些修改使得其可以自动记录成功以及错误日志

创建事件

  1. <?php
  2. namespace App\Light\HttpClient;
  3. use Illuminate\Contracts\Support\Arrayable;
  4. class HttpSendSuccessEvent implements \JsonSerializable,Arrayable
  5. {
  6. public $request_id; //请求标识
  7. public $url; //url
  8. public $params; //请求参数
  9. public $method; //请求方法
  10. public $created_at; //请求时间
  11. public $response; //响应内容
  12. public $response_header; //响应头
  13. public $request_header; //请求头
  14. public $handler_stats; //请求信息
  15. public $tag; //标签
  16. public function toArray()
  17. {
  18. return [
  19. 'request_id' => $this->request_id,
  20. 'url' => $this->url,
  21. 'params' => $this->params,
  22. 'method' => $this->method,
  23. 'created_at' => $this->created_at,
  24. 'response' => $this->response,
  25. 'response_header' => $this->response_header,
  26. 'request_header' => $this->request_header,
  27. 'handler_stats' => $this->handler_stats,
  28. 'tag' => $this->tag,
  29. ];
  30. }
  31. public function jsonSerialize()
  32. {
  33. return $this->toArray();
  34. }
  35. public function __toString()
  36. {
  37. return json_encode($this, JSON_UNESCAPED_UNICODE);
  38. }
  39. }
  1. <?php
  2. namespace App\Light\HttpClient;
  3. use Illuminate\Contracts\Support\Arrayable;
  4. class HttpSendFailEvent implements \JsonSerializable,Arrayable
  5. {
  6. public $request_id; //请求标识
  7. public $url; //url
  8. public $params; //请求参数
  9. public $method; //请求方法
  10. public $created_at; //请求时间
  11. public $error; //错误信息
  12. public $response_header; //响应头
  13. public $tag; //标签
  14. public function toArray()
  15. {
  16. return [
  17. 'request_id' => $this->request_id,
  18. 'url' => $this->url,
  19. 'params' => $this->params,
  20. 'method' => $this->method,
  21. 'created_at' => $this->created_at,
  22. 'error' => $this->error,
  23. 'response_header' => $this->response_header,
  24. 'tag' => $this->tag,
  25. ];
  26. }
  27. public function jsonSerialize()
  28. {
  29. return $this->toArray();
  30. }
  31. public function __toString()
  32. {
  33. return json_encode($this, JSON_UNESCAPED_UNICODE);
  34. }
  35. }

增加日志逻辑

修改httpclient包中PendingReques类中的send方法

  1. public function send(string $method, string $url, array $options = [])
  2. {
  3. $url = ltrim(rtrim($this->baseUrl, '/') . '/' . ltrim($url, '/'), '/');
  4. if (isset($options[$this->bodyFormat])) {
  5. if ($this->bodyFormat === 'multipart') {
  6. $options[$this->bodyFormat] = $this->parseMultipartBodyFormat($options[$this->bodyFormat]);
  7. } elseif ($this->bodyFormat === 'body') {
  8. $options[$this->bodyFormat] = $this->pendingBody;
  9. }
  10. if (is_array($options[$this->bodyFormat])) {
  11. $options[$this->bodyFormat] = array_merge(
  12. $options[$this->bodyFormat], $this->pendingFiles
  13. );
  14. }
  15. }
  16. [$this->pendingBody, $this->pendingFiles] = [null, []];
  17. return retry($this->tries ?? 1, function () use ($method, $url, $options) {
  18. try {
  19. $laravelData = $this->parseRequestData($method, $url, $options);
  20. return tap(new Response($this->buildClient()->request($method, $url, $this->mergeOptions([
  21. 'laravel_data' => $laravelData,
  22. 'on_stats' => function ($transferStats) {
  23. $this->transferStats = $transferStats;
  24. },
  25. ], $options))), function ($response) use ($method, $url, $options) {
  26. $response->cookies = $this->cookies;
  27. $response->transferStats = $this->transferStats;
  28. //新加入
  29. //生产事件
  30. $event = new HttpSendSuccessEvent();
  31. $event->url = $url;
  32. $event->params = $options;
  33. $event->method = $method;
  34. $event->created_at = Carbon::now()->toDateTimeString();
  35. $event->response = $response->body();
  36. $event->request_header = $response->transferStats->getRequest()->getHeaders();
  37. $event->response_header = $response->headers();
  38. $event->handler_stats = $response->handlerStats();
  39. //发事件
  40. event($event);
  41. if ($this->tries > 1 && !$response->successful()) {
  42. $response->throw();
  43. }
  44. });
  45. } catch (ConnectException $e) {
  46. //新加入
  47. //生产事件
  48. $event = new HttpSendFailEvent();
  49. $event->url = $url;
  50. $event->params = $options;
  51. $event->method = $method;
  52. $event->created_at = Carbon::now()->toDateTimeString();
  53. $event->error = $e->getHandlerContext();
  54. $event->request_header = $e->getRequest()->getHeaders();
  55. //发事件
  56. event($event);
  57. throw new ConnectionException($e->getMessage(), 0, $e);
  58. }
  59. }, $this->retryDelay ?? 100);
  60. }

创建事件处理器

这里使用了生成请求唯一标识和terminate中间件 参考laravel技巧—请求日志laravel技巧-terminate延迟处理

  1. <?php
  2. namespace App\Light\HttpClient;
  3. use App\Light\RequestID\ResID;
  4. use App\Light\TerminateHandle\TerminateEvent;
  5. use App\Light\TerminateHandle\TerminateHandle;
  6. use Carbon\Carbon;
  7. use Illuminate\Support\Facades\DB;
  8. class HttpSendSuccessEventListener
  9. {
  10. public function handle(HttpSendSuccessEvent $event)
  11. {
  12. //延迟记录
  13. TerminateHandle::add(new TerminateEvent(function () use ($event) {
  14. $event->request_id = ResID::get(); //请求标识
  15. DB::connection('mongodb')
  16. ->collection('curl_' . Carbon::now()->format('Ym'))
  17. ->insert($event->toArray());
  18. }));
  19. }
  20. }
  1. <?php
  2. namespace App\Light\HttpClient;
  3. use App\Light\RequestID\ResID;
  4. use App\Light\TerminateHandle\TerminateEvent;
  5. use App\Light\TerminateHandle\TerminateHandle;
  6. use Carbon\Carbon;
  7. use Illuminate\Support\Facades\DB;
  8. class HttpSendFailEventListener
  9. {
  10. public function handle(HttpSendFailEvent $event)
  11. {
  12. //延迟记录
  13. TerminateHandle::add(new TerminateEvent(function () use ($event) {
  14. try {
  15. $event->request_id = ResID::get(); //请求标识
  16. DB::connection('mongodb')
  17. ->collection('curl_error_' . Carbon::now()->format('Ym'))
  18. ->insert($event->toArray());
  19. } catch (\Exception $exception) {
  20. }
  21. }));
  22. }
  23. }

注册事件处理器

  1. class EventServiceProvider extends ServiceProvider
  2. {
  3. /**
  4. * The event listener mappings for the application.
  5. *
  6. * @var array
  7. */
  8. protected $listen = [
  9. //新增
  10. HttpSendSuccessEvent::class => [
  11. HttpSendSuccessEventListener::class
  12. ],
  13. HttpSendFailEvent::class => [
  14. HttpSendFailEventListener::class
  15. ],
  16. ];

查看结果

成功结果
image.png
失败结果
image.png