Nuxt 3 useFetch封装后在Pinia中二次调用未发送请求问题
Nuxt3 + Pinia中useFetch封装后二次调用不发请求的问题
问题描述
我在Pinia的用户登录函数中使用Nuxt3的useFetch封装了useApiFetch方法。首次调用该函数时请求发送成功,行为符合预期;但第二次调用(例如用户修改API Key后),通过浏览器网络面板确认并未发送请求。预期行为是每次调用该方法时,都能向后端发送请求。
相关代码
Pinia 用户状态管理(user.ts)
import { defineStore } from 'pinia' import { useApiFetch } from '~/composables/useApiFetch' export const useUserStore = defineStore('user', () => { const user = ref({}) async function handleLogin(apiKey: string) { const { data, error } = await useApiFetch('/user/login', { params: { apiKey }, watch: false, }) user.value = data.value console.log(user.value) } return { handleLogin, user } })
登录页面(index.vue)
<template> <div class="h-screen flex items-center justify-center"> <div class="surface-card p-12 shadow-2 border-round lg:w-1/3 shadow-gray-400 shadow-2xl rounded border-primary-500"> <div class="text-center mb-5"> <img src="https://placehold.co/200x70" alt="Image" class="mb-3 mx-auto" /> <div class="text-900 text-3xl font-medium mb-3">Welcome Back</div> <span class="text-600 font-medium line-height-3">Please use a public torn api key to access.</span> </div> <div> <label for="apikey" class="block text-900 font-medium mb-2">API Key</label> <InputText id="apikey" v-model="apiKey" :invalid="apiKey.length !== 16 && apiKey.length > 0" :disabled="isLoading" type="text" class="w-full mb-3" /> <Button label="Sign In" icon="pi pi-user" :loading="isLoading" class="w-full" @click="handleLogin"></Button> </div> </div> </div> </template> <script setup> import { useUserStore } from '~/stores/user.ts' const userStore = useUserStore() const apiKey = ref('') const isLoading = ref(false) async function handleLogin() { isLoading.value = true await userStore.handleLogin(apiKey.value) isLoading.value = false } </script>
API请求封装(useApiFetch.ts)
import { defu } from 'defu' import { useUserStore } from '~/stores/user' export function useApiFetch(url: string, options = {}) { const { $toast } = useNuxtApp() const uS = useUserStore() const { user } = storeToRefs(uS) const defaults = { baseURL: 'http://localhost:3001', onRequest({ request, options }) { // Set the request headers options.headers = options.headers || { apiKey: user.value.apiKey, } }, onRequestError({ request, options, error }) { console.log('onRequestError', error) }, onResponseError({ request, response, options }) { // Handle the response errors $toast.add({ severity: 'error', summary: 'Error', detail: response._data.error.error, }) }, } const params = defu(options, defaults) return useFetch(url, params) }
解决方案
问题根源
Nuxt3的useFetch默认会对请求结果进行缓存,如果请求的URL和参数未发生变化,就会直接返回缓存数据,不会重新发起网络请求。此外,useApiFetch的onRequest钩子存在逻辑问题:登录场景下,store中的user.value.apiKey尚未更新,导致请求头设置不符合预期。
修复步骤
- 强制绕过缓存:给
useFetch添加唯一key参数,或直接关闭缓存机制。 - 修正请求头逻辑:优先使用请求参数中的
apiKey,确保登录时请求头正确。
修改后的代码
1. 更新Pinia的handleLogin方法
async function handleLogin(apiKey: string) { const { data, error } = await useApiFetch('/user/login', { params: { apiKey }, watch: false, // 生成唯一key,强制触发新请求 key: `login-request-${apiKey}-${Date.now()}`, // 直接关闭缓存(二选一即可,也可在useApiFetch默认配置中全局设置) cache: 'no-store' }) user.value = data.value console.log(user.value) }
2. 修正useApiFetch的onRequest钩子
const defaults = { baseURL: 'http://localhost:3001', // 可选:全局关闭所有useApiFetch请求的缓存 cache: 'no-store', onRequest({ request, options }) { // 优先使用请求参数中的apiKey,适配登录场景 const targetApiKey = options.params?.apiKey || user.value.apiKey options.headers = options.headers || {} options.headers.apiKey = targetApiKey }, onRequestError({ request, options, error }) { console.log('onRequestError', error) }, onResponseError({ request, response, options }) { $toast.add({ severity: 'error', summary: 'Error', detail: response._data.error.error, }) }, }
内容的提问来源于stack exchange,提问作者OliverKhl
相关产品推荐
相关产品推荐

