Nuxt 3.8.0 useFetch Error Cache 的問題

useFetch Bug

前言

最近在使用 Nuxt3 的 useFetch 的時候發生了一點狀況,也就是 API 發生 Error 之後就無法再次觸發 API 的問題,所以這邊就來記錄一下。

問題

首先我的 Nuxt 版本是 Nuxt 3.8.0 with Nitro 2.7.2

然後我在使用 useFetch 的時候發生了一點問題,就是當 API 發生 Error 之後,就無法再次觸發 API QQ

狀況如下 Gif:

API Error

基本上你可以發現當我點一下「點我發生錯誤」的 Button 按鈕之後,確實會發生 400 錯誤,接著我後續不管怎麼點都不會再次觸發 API

那程式碼呢?其實程式碼很單純:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script setup>
const apiPostError = () => {
useFetch('/api/hello', {
method: 'POST',
body: JSON.stringify({
}),
})
}


</script>

<template>
<div>
<button @click="apiPostError">點我發生錯誤</button>
</div>
</template>

而這個 /api/hello 也只是我用 Nuxt3 的 API Routes 建立的一個 API

1
2
3
4
5
6
7
8
9
10
11
export default defineEventHandler((event) => {
const id = parseInt(event.context.params.id)

if (!Number.isInteger(id)) {
throw createError({
statusCode: 400,
statusMessage: 'ID should be an integer',
})
}
return 'All good'
})

那…這個問題會影響在哪邊呢?如果使用者在你的畫面上登入時,第一次輸入錯誤的帳號密碼,接著第二次輸入正確的帳號密碼,那麼就會發生無法登入的問題,因為 API 無法被觸發。

解決方式

剛剛有提到一個情境是關於登入的問題,我們使用者一定是很容易會輸入錯誤的帳號密碼,所以不管怎樣這個問題是必須被解決的。

基本上只要發生 4xx or 5xx 都是會觸發這個問題的,但是我們只要重新整理畫面後,就又可以再次觸發 API,這樣就代表一件事情,也就是我們的 Error 被 Catch 住了。

剛好我也有在官方 Issues 找到相關問題

而官方也發起了一個 PR(fix(nuxt): only skip refetching errors when hydrating)來解決這個問題,內容主要是將…

1
if (asyncData.error.value || (fetchOnServer && nuxt.isHydrating && hasCachedData())) ...

調整為

1
if (fetchOnServer && nuxt.isHydrating && (asyncData.error.value || hasCachedData())) ...

雖然官方已經 Merge 進去了,但還沒有釋出新的版本,所以我們只能先自己解決這個問題 QQ

講了那麼多,我們該怎麼解決呢?這邊我們可以用最簡單的方式,也就是將 useFetcherror 解構出來,接著當 error 發生錯誤時,就將它設定為 null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script setup>
const apiPostError = () => {
const { error } = useFetch('/api/hello', {
method: 'POST',
body: JSON.stringify({
}),
})

if(error.value) {
error.value = null
console.log(error.value)
}
}
</script>

透過這個最簡單的方式,當你 API 發生錯誤之後,也可以繼續觸發 API 了!

恢復正常

基本上 useFetch 回傳的資料會是一個 ref,所以我們就是利用 Proxy 的特性來解決這個問題,也剛好 Nuxt3 官方沒有替回傳的資料加上 readonly,不然我們就無法這樣子做了。

但是這樣子做有一個問題,就是當你的 API 有發生錯誤時,你就無法吐出相對應後端給予的錯誤訊息,所以其實你可以這樣改寫:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script setup>
const apiPostError = () => {
const { error } = useFetch('/api/hello', {
method: 'POST',
body: JSON.stringify({
}),
})

if(error.value) {
const cacheError = JSON.parse(JSON.stringify(error.value))
error.value = null
console.log(cacheError)
}
}
</script>

這樣至少你就可以拿到後端給予的錯誤訊息並吐出來給使用者。

那麼這個解法也只是一個過渡期而已,官方預計下個版本就會修正了,所以如果可以的話,我滿推薦你直接升級至 3.8.0 以上,因為這個問題其實會影響到很多地方,舉凡…像是登入、表單驗證等等,因此如果你的專案有使用到 useFetch 的話,那麼我會建議你注意一下唷~

Note
目前這個問題 Nuxt 官方已經在 3.8.1 修正囉~

Liker 讚賞

這篇文章如果對你有幫助,你可以花 30 秒登入 LikeCoin 並點擊下方拍手按鈕(最多五下)免費支持與牡蠣鼓勵我。
或者你可以也可以請我「喝一杯咖啡(Donate)」。

Buy Me A Coffee Buy Me A Coffee

Google AD

撰寫一篇文章其實真的很花時間,如果你願意「關閉 Adblock (廣告阻擋器)」來支持我的話,我會非常感謝你 ヽ(・∀・)ノ