iT邦幫忙

2024 iThome 鐵人賽

DAY 16
0
Modern Web

後端菜雞仔想學 Laravel系列 第 16

查找問題的好方法:來 log log 吧!

  • 分享至 

  • xImage
  •  

發生過的問題

昨天晚上突然想到,使用 Postman 測試 [ PATCH ] api/products/{product} :修改單一產品部份資料 這支 API 時,我有遇過一個問題,所以今天要來分享一下。
這個問題我自己覺得蠻重要的,也許有跟我一樣的小夥伴遇過這樣的問題。(還是只有我XD)

問題:明明顯示出 200 狀態碼及「商品更新完成」的訊息,但仔細一看,顯示出的商品資訊仍然是「未修改前的內容」。

例如:

當使用 Postman 發送 PATCH 請求來更新產品名稱時,請求內容如下:

{
    "product_name": "古早味紅茶"
}

但伺服器回應如下:

{
    "message": "商品資料更新完成!",
    "product": {
        "id": 3,
        "type_id": 2,
        "product_name": "杏仁瓦片",
        "product_description": "600ml,阿嬤的古早味,最對味!",
        "price": 40,
        "created_at": "2024-09-30 09:37",
        "updated_at": "2024-09-30 09:37"
    }
}

雖然顯示更新成功訊息,但卻顯示產品名稱並未更新。
菜雞仔如我,當時特別震驚,不知道為什麼發生這樣的事情(皺眉)

深呼吸後,就先來找出問題來源,我們來 log log 吧!

必須說一下,我當時真的很菜,我還不太會使用 log 去查看錯誤日誌,當然也不會什麼 dd 或其他方式,我直接丟 GPT 詢問找出問題的方法,這是 GPT 給的其中一個建議,後來認真理解後,用 log 記錄這個方法在往後真的幫助我好多好多~(拭淚)


找出問題來源的方法

使用 \Log::info() 來記錄日誌

在 Laravel 框架中,Log 是一個很好用的日誌系統,讓開發者可以方便地記錄應用程式運行時的各種資訊。

Log 提供了多種方法來記錄不同層級的日誌,例如 info、warning、error 等等。
其中 info 用於記錄一般的資訊性訊息。

這些記錄通常位於 storage/logs/laravel.log

為什麼要加 \ 呢?(我當時很疑惑)

當你在 Laravel 裡用 \Log::info() 的時候,前面那個反斜線 \ 就像是在告訴 PHP:「我要的是全域的 Log,那個 Laravel 預設的 Log,不是其他的!」

因為 Laravel 的程式碼通常都在不同的命名空間裡(例如 App\Http\Controllers 這種分類),所以如果你直接寫 Log::info(),PHP 可能會以為你要找的是這個命名空間下的 Log,結果它可能找不到,然後報錯。

簡單來說,反斜線就像是在導航一樣,加了反斜線以後,就不會遇到命名空間搞混的問題。

來用用看吧!

原本的更新產品邏輯

例如:更新產品名稱
先驗證需要更改的名稱是否符合我自訂的規則,符合的話便更新,更新後便回傳更新後的完整資料。

  1. 使用 \Log::info() 在每一個步驟記錄
  2. 並在 laravel.log 中確認請求資料是否有進來、是否符合驗證規則,還有查看每一個步驟輸出的結果。

ProductController 的 update 方法:

public function update(Request $request, Product $product)
{
    // 記錄原始請求資料
    \Log::info('Raw request data: ', $request->all());

    // 驗證規則
    $rules = [
        'type_id' => 'sometimes|integer|min:0',
        'product_name' => 'sometimes|string|max:255',
        'product_description' => 'nullable',
        'price' => 'sometimes|integer|min:0',
    ];

    // 驗證請求資料
    $validatedData = $request->validate($rules);

    // 記錄驗證後的資料
    \Log::info('Validated request data: ', $validatedData);

    // 更新產品資料
    $product->update($validatedData);

    // 強制同步資料庫
    $product->refresh();

    // 記錄更新後的產品資料
    \Log::info('Updated product: ', $product->toArray());

    // 返回更新後的資料
    return response()->json([
        'message' => '商品資料更新完成!',
        'product' => $product,
    ], 200);
}

透過以上方法發現問題:請求資料未正確傳遞

查看 laravel.log 時,發現 Raw request data 是空的,這表示請求的資料從一開始就未正確傳遞。

檢查 Postman 設定後,確認沒有設定 Headers : Content-Type:application/json,僅有設定:Accept: application/json

當時,我對於 Header 並沒有很了解,基本上只有照著基礎操作文章設定而已,沒有去認真理解我設定的東西是什麼。

所以在這邊發生問題時,在查找問題的過程中又更加對某些部份有所了解,果然經驗都是累積的!(插腰點頭)


那什麼是 Content-Type 跟 Accept 呢?
以下整理 GPT 的回覆:

Content-Type 和 Accept 的差別

在進行網路請求時,Content-Type 和 Accept 是兩個經常會遇到的重要 Header。它們雖然看起來類似,但功能完全不一樣。

Content-Type

是用來告訴伺服器或接收端:「我發送給你的資料是什麼格式」。
這樣,接收端就可以依照這個 Header 來正確處理和解析資料。

例如:
如果你傳的是 JSON 格式的資料,你會在請求的 Content-Type 裡寫上 application/json。這樣伺服器就知道你傳的資料是 JSON 格式,它就會依照這個格式去解析你的資料,確保資料能被系統理解。

Accept

是用來告訴伺服器:「我希望接收到的回應是什麼格式」。
當你發送請求時,會告訴伺服器:「我想要你回傳 JSON 格式的資料」,那伺服器就會依照你的要求,把回應的資料格式化成你希望的樣子。

例如:
當你設定 Accept: application/json,就是告訴伺服器:「我想要 JSON 格式的回應哦!」,伺服器收到這個請求後,會試著把資料回傳成 JSON 格式。

建議能參考這篇文章:學習筆記 | 什麼是網路請求(HTTP request)
我覺得這篇文章寫得很易懂!


正確的問題來源

使用 Postman 測試時,我沒有告訴它發送的資料是什麼格式,也就是沒有設定Content-Type:application/json

解決問題

確保 Postman 設定正確

  1. URL: http://127.0.0.1:8000/api/products/3
  2. Method: PATCH
  3. Headers:
  • Accept: application/json
  • Content-Type: application/json
  1. Body: 選擇 raw 並設定格式為 JSON,輸入以下內容:

    {
        "product_name": "古早味紅茶"
    }
    

確認 Postman 測試 PATCH 請求的結果

{
    "message": "商品資料更新完成!",
    "product": {
        "id": 3,
        "type_id": 2,
        "product_name": "古早味紅茶",
        "product_description": "600ml,阿嬤的古早味,最對味!",
        "price": 40,
        "created_at": "2024-09-30 09:37",
        "updated_at": "2024-09-30 12:48"
    }
}

正確設定 Content-Type 後,再次發送請求,已正確更新產品資料並回傳更新後的產品資料。


上一篇
修改單一產品部分資料:sometimes 規則
下一篇
Route Model Binding:Laravel 神奇的查詢利器
系列文
後端菜雞仔想學 Laravel30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言