You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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尚未更新,导致请求头设置不符合预期。

修复步骤

  1. 强制绕过缓存:给useFetch添加唯一key参数,或直接关闭缓存机制。
  2. 修正请求头逻辑:优先使用请求参数中的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 04:00:05