Next.js讀cookie提示Promise:先await cookies再取值

升級Next.js後,原本的 cookies().get('theme')提示不是可直接使用的cookie store。先看你呼叫的是next/headers提供的cookies函式。現行API是非同步的,應先await取得store,再讀其中的值。

這個修正處理的是伺服器讀取當次請求cookie的介面,不是把cookie搬到全域變數,也不是在瀏覽器改用localStorage。讀者先用兩份合成Cookie標頭測同一條Route Handler,就能確認它讀的是各自請求帶來的值。

先取得store,再呼叫get

下面是最小的App Router Route Handler。它只讀demo_theme並回JSON,不登入、不寫cookie,也不連資料庫。

import { cookies } from 'next/headers'
export async function GET() {
  const store = await cookies()
  const theme = store.get('demo_theme')?.value ?? 'none'
  return Response.json({ theme })
}

將它放在 app/cookie/route.js,GET處理函式要是async,才能在裡面await。先解析cookies這個非同步操作,再對store呼叫get。不要寫成 await cookies().get(...),因為那會在等待之前先嘗試對Promise呼叫get。

也不要忘記取得的是cookie物件,需要讀value。.get()找不到該名稱時可能沒有物件,所以範例採可選鏈與預設字串。這個預設只讓示範結果容易辨認,不是你所有業務功能都應採相同的缺值策略。

舊版同步例子不代表目前介面

官方升級指南說明,Next.js15引入非同步的請求API,包含cookies。舊版文件或片段可能仍用同步寫法;維護站點時先確認package與鎖定版本,再按對應指南改。

本文真案例是Next.js16.3.8、React19.3.0,使用await cookies。不把舊站曾經可同步讀取當作現版可依賴的行為,也不要求每個舊專案只因看到本文就立刻升級。這份教學解決的是目前已使用非同步介面的程式怎麼正確取值。

如果編輯器還是顯示與文件不符的型別,也要核實際安裝版本與匯入來源。另一個套件裡同名的cookies方法,不一定是這個API。先把它來自哪裡讀清楚,避免只在呼叫前後加await卻改錯東西。

同一路徑,兩個請求各帶自己的值

本機測試可以分別送light與dark。這些是合成偏好值,不含帳戶、工作階段或權杖。curl的Cookie標頭讓你直接看到輸入,不需要先操作真會員登入。

curl -H 'Cookie: demo_theme=light' http://127.0.0.1:3000/cookie
curl -H 'Cookie: demo_theme=dark' http://127.0.0.1:3000/cookie

本文實際HTTP結果是兩次都回200;第一份JSON的theme是light,第二份是dark。這說明同一個處理函式讀到了當次不同的Cookie標頭,不是把第一次讀到的store留著讓所有請求共用。

這份測試沒有觀察瀏覽器自動送cookie的範圍,也沒有修改正式cookie配置。接回網站後,要再核瀏覽器真正發出的請求是否帶預期名稱與值。手動指定標頭能驗證解析介面,不能取代真瀏覽器的domain、path與發送條件。

cookie是請求資料,不是全域設定

不要在模組最外層提前讀cookies,再把結果當成全站固定偏好。cookie跟當次請求有關,應在合適的伺服器請求上下文裡讀。把某一次的值快取成大家共用,會讓不同使用者的結果混在一起。

如果頁面需要依偏好選擇畫面,可以在Server Component裡await cookies,取得並整理允許值,再傳必要資料給顯示元件。選dark或light等固定集合時,對未知值保留明確的預設,不要把任意cookie字串直接當成設定名稱或資料查詢。

讀到cookie也不表示它可信或能單獨決定授權。本例只是顯示合成theme;真登入與資源權限仍沿既有服務驗證。把這兩種需求分開,能讓取值示例保持簡單,不會把任意客戶端提供的字串當成已核身分。

NextRequest.cookies是另一個入口

Route Handler若使用NextRequest,該請求物件也有自己的cookies介面。它與next/headers的cookies函式不是同一個呼叫方式,不能因為名字相似就交換使用,或對兩者都機械加相同await。

export function GET(request) {
  const theme = request.cookies.get('demo_theme')?.value ?? 'none'
  return Response.json({ theme })
}

這段只示意NextRequest的介面,實際使用時需讓函式的請求型別與相關匯入符合你的專案。本文真案例測的是next/headers的await cookies,沒有把這個替代寫法稱為同一份已經實測的程式。

選一個符合上下文的入口即可,不必在同一個函式把兩個store都讀一遍。維護者看到取值來源一致,也比較容易判斷後來的錯誤是請求沒有帶值,還是介面被用錯。

讀取與寫入限制要分清

cookies API能讀當次請求,也在合適的Server Action或Route Handler情境提供寫入方法。讀到值,不表示Server Component任意位置都能改瀏覽器cookie。寫入屬於回應的一部分,應按官方API與應用程式的回應流程安排。

本文沒有執行set或delete,也不改domain、secure、sameSite等設定。若你的工作是保存偏好,要另核回應中的Set-Cookie與之後的請求,而不是只看到store對象裡有新值就當成瀏覽器已保存。

同樣地,瀏覽器某段JavaScript讀不到cookie,並不必然代表伺服器沒收到它。看實際請求與相關cookie屬性,才能知道是讀取介面還是發送範圍的問題;不要為了除錯就任意降低原本的配置條件。

缺值時,先查名稱與請求

若JSON始終是none,先核名稱是否叫demo_theme、Request標頭是否有它,再看get的返回與value。讀取Promise的問題修好後,下一個問題可能只是名稱不一致,不需要把整個頁面改為Client。

在測試站可以加一次不帶cookie的請求,確認缺值分支符合需求;這是讀者可補做的分支,不冒充本文兩次light/dark已涵蓋所有情況。需要驗證多個cookie時逐一記錄合成名稱與結果,不要輸出正式Cookie標頭。

最終保留兩個不同輸入與對應結果,再接回真正頁面。非同步API的正確順序很短:await取得store,get查名稱,讀value並處理缺席。剩下的發送範圍、保存與業務用途,則依你的網站契約各自核對。

從瀏覽器測時,別混淆兩種標頭

請求送出的Cookie標頭包含名稱與值;伺服器設定cookie則使用回應的Set-Cookie。本文curl主動指定的是前者,只讓Route Handler取得一份已提供的輸入,不會建立瀏覽器之後自動保留的cookie。若在網站測偏好保存,要把寫入回應與下一次請求一起核對。

瀏覽器儲存區看得到某個cookie,也不代表每條路徑都會送它。請求的domain、path、協定與其他屬性會影響傳送;這種情況應從Network中實際的Cookie標頭查起,不要因為get回不到值就一直調await。框架只能讀目前收到的資料,不會替你補送不符合範圍的cookie。

同一名稱可能在不同設定範圍出現,也應核對你要讀的是哪份請求資料。需要調查多個值時,可依API提供的查找方式與合成資料比較,別把整份正式cookie內容顯示在頁面。修非同步介面時保持取值最小,才能讓來源與用途一眼可辨。

none只是範例的缺值結果,不代表瀏覽器主動送來這個偏好。

參考資料

原文鏈接:https://wntheme.com/next-await-cookies-request-value/,轉載請註明出處。
0

評論0

顯示驗證碼
沒有帳號?註冊  忘記密碼?