實作
過濾函式
新增 app/Helpers/Helper.php 檔,建立一個消毒函式,把請求中的敏感資訊過濾掉。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 
 | <?php
 namespace App\Helpers;
 
 class Helper
 {
 static function sanitize($data)
 {
 $fields =  ['password', 'secret', 'token'];
 
 if (is_array($data)) {
 foreach ($data as $key => $value) {
 if (is_array($value)) {
 $data[$key] = self::sanitize($value, $fields);
 }
 foreach ($fields as $field) {
 if (stripos($key, $field) !== false) {
 $data[$key] = '******';
 }
 }
 }
 }
 
 return $data;
 }
 }
 
 | 
建立中介層
建立 app/Http/Middleware/AssignRequestId.php 檔,為所有日誌添加共用的 REQUEST_ID 資訊。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 
 | <?php
 namespace App\Http\Middleware;
 
 use Closure;
 use Illuminate\Http\Request;
 use Illuminate\Support\Str;
 use Illuminate\Support\Facades\Log;
 use Symfony\Component\HttpFoundation\Response;
 
 class AssignRequestId
 {
 
 
 
 
 
 public function handle(Request $request, Closure $next): Response
 {
 $requestId = (string) Str::uuid();
 
 Log::withContext([
 'REQUEST_ID' => $requestId
 ]);
 
 $request->headers->set('Request-Id', $requestId);
 
 return $next($request);
 }
 }
 
 | 
建立 app/Http/Middleware/LogRequestResponse.php 檔,記錄從前端發送過來的請求,以及從後端發送回去的響應。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 
 | <?php
 namespace App\Http\Middleware;
 
 use App\Helpers\Helper;
 use Closure;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Log;
 use Symfony\Component\HttpFoundation\Response;
 
 class LogRequestResponse
 {
 
 
 
 
 
 public function handle(Request $request, Closure $next): Response
 {
 $response = $next($request);
 
 Log::info('LOG_REQUEST_RESPONSE', [
 'REQUEST_METHOD' => $request->method(),
 'REQUEST_URL' => $request->url(),
 'REQUEST_BODY' => Helper::sanitize(json_decode(str_replace("\\n", '', $request->getContent()), true)),
 'RESPONSE_STATUS' => $response->getStatusCode(),
 'RESPONSE_BODY' => Helper::sanitize(json_decode(str_replace("\\n", '', $response->getContent()), true)),
 'TIME' => now(),
 ]);
 
 return $response;
 }
 }
 
 | 
修改 app/Http/Kernel.php 檔,將中介層添加到 api 列表中。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 
 | <?php
 namespace App\Http;
 
 use Illuminate\Foundation\Http\Kernel as HttpKernel;
 
 class Kernel extends HttpKernel
 {
 
 
 
 
 
 
 
 protected $middlewareGroups = [
 
 
 'api' => [
 
 \App\Http\Middleware\AssignRequestId::class,
 \App\Http\Middleware\LogRequestResponse::class,
 ],
 ];
 
 
 }
 
 | 
建立監聽器
建立 app/Listeners/LogRequestSending.php 檔,記錄後端發送給第三方服務的請求。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 
 | <?php
 namespace App\Listeners;
 
 use App\Helpers\Helper;
 use Illuminate\Contracts\Queue\ShouldQueue;
 use Illuminate\Queue\InteractsWithQueue;
 use Illuminate\Support\Facades\Log;
 
 class LogRequestSending
 {
 
 
 
 public function __construct()
 {
 
 }
 
 
 
 
 public function handle(object $event): void
 {
 
 $request = $event->request;
 
 Log::info('LOG_REQUEST_SENDING', [
 'REQUEST_METHOD' => $request->method(),
 'REQUEST_URL' => $request->url(),
 'REQUEST_BODY' => Helper::sanitize(json_decode(str_replace("\\n", '', $request->body()), true)),
 'TIME' => now(),
 ]);
 }
 }
 
 | 
建立 app/Listeners/LogResponseReceived.php 檔,記錄後端接收到第三方服務的響應。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 
 | <?php
 namespace App\Listeners;
 
 use App\Helpers\Helper;
 use Illuminate\Contracts\Queue\ShouldQueue;
 use Illuminate\Queue\InteractsWithQueue;
 use Illuminate\Support\Str;
 use Illuminate\Support\Facades\Log;
 
 class LogResponseReceived
 {
 
 
 
 public function __construct()
 {
 
 }
 
 
 
 
 public function handle(object $event): void
 {
 
 $request = $event->request;
 
 
 $response = $event->response;
 
 Log::info('LOG_RESPONSE_RECEIVED', [
 'REQUEST_METHOD' => $request->method(),
 'REQUEST_URL' => $request->url(),
 'REQUEST_BODY' => Helper::sanitize(json_decode(str_replace("\\n", '', $request->body()), true)),
 'RESPONSE_STATUS' => $response->status(),
 'RESPONSE_BODY' => Helper::sanitize(json_decode(str_replace("\\n", '', $response->body()), true)),
 'TIME' => now(),
 ]);
 }
 }
 
 | 
修改 app/Providers/EventServiceProvider.php 檔,將監聽器添加到 listen 列表中。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 
 | <?php
 namespace App\Providers;
 
 use App\Listeners\LogRequestSending;
 use App\Listeners\LogResponseReceived;
 use Illuminate\Auth\Events\Registered;
 use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
 use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
 use Illuminate\Http\Client\Events\RequestSending;
 use Illuminate\Http\Client\Events\ResponseReceived;
 use Illuminate\Support\Facades\Event;
 
 class EventServiceProvider extends ServiceProvider
 {
 
 
 
 
 
 protected $listen = [
 Registered::class => [
 SendEmailVerificationNotification::class,
 ],
 RequestSending::class => [
 LogRequestSending::class,
 ],
 ResponseReceived::class => [
 LogResponseReceived::class,
 ],
 ];
 
 
 
 
 public function boot(): void
 {
 
 }
 
 
 
 
 public function shouldDiscoverEvents(): bool
 {
 return false;
 }
 }
 
 | 
參考資料