nuxt3.0学习-二、nuxt3.0的请求相关内容、状态管理(useState/Pinia)、cookie管理(useCookie)、token续期

文章详细介绍了Nuxt3.0提供的数据访问API,包括$fetch、useAsyncData、useLazyAsyncData和useFetch的用法和区别。同时,展示了如何封装HTTP请求,使用useState和useCookie进行状态和cookie管理,并提到了token的续期策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

请求相关内容

nuxt3.0提供的多种数据访问 API

上一次是nuxt3.0的安装和约定式的使用
接下来就是使用请求调整,Nuxt3 中提供的多种数据访问 API:

  1. $fetch;
    使用时机:
    首屏渲染,调用发生在服务端;
    客户端激活之后,调用发生在客户端。
  2. useAsyncData;
    该方法和 useFetch 相比功能上是相同的,但是更底层,使用方法类似于 ahooks 库中的 useRequest,我们需要提供一个用于缓存去重的 key 和数据请求的处理函数。也就是说,useFetch 相当于:useAsyncData(key, () => $fetch(url))。
  3. useLazyAsyncData;
    该方法等效于useFetch设置了lazy选项为 true,不同之处在于它不会阻塞路由导航,这意味着我们需要处理 data 为 null 的情况(或者通过 default 选项给 data 设置一个默认值)。
  4. useFetch;
    页面、组件或者插件中可以使用useFetch获取任意 URL 资源。useFetch是对useAsyncData和$fetch的封装,只需传入请求的 URL 或者一个请求函数即可,一些选项会自动填入,用起来最简洁,是最推荐的数据获取方式。
  5. useLazyFetch
    该方法等效于useFetch设置了lazy选项为 true,不同之处在于它不会阻塞路由导航,这意味着我们需要处理 data 为 null 的情况(或者通过 default 选项给 data 设置一个默认值)。

使用封装

$fetch、useFetch封装方法

////// http请求封装 //////
import { ElMessage } from 'element-plus'

export const fetchConfig = {
    baseURL: getBaseUrl(),//请求配置
    headers: { ContentType: 'multipart/form-data' }
}

//请求体封装
function useGetFetchOptions(options = {}){
    options.baseURL = options.baseURL ?? fetchConfig.baseURL
    options.headers = options.headers ?? {
      ContentType: fetchConfig.headers.ContentType
    }
    options.initialCache = options.initialCache ?? false
    options.lazy = options.lazy ?? false
    options.showError = options.showError ?? true
    options.needReject = options.needReject ?? false

    // 用户登录,默认传token
    const Authorization = useCookie("cookies名称")
   
    // if(Authorization.value){ 
      options.headers.Authorizations = Authorization.value
    // }

    return options
}

//http请求封装
export async function useHttp(key,url,options = {}){
    options = useGetFetchOptions(options)
    options.key = key

    if(options.$){
        // 通过插件或中间件调用时
        return new Promise((resolve, reject) => {
          $fetch(url, options).then(res => {
            if (res.code == 200) {
            resolve(res);
            const toggleTokenBool = useState('tokenBool')
            toggleTokenBool.value = false
          } else if (res.code == 20001) {
            // token失效处理
            reject(res)
            const toggleTokenBool = useState('tokenBool')
            if(!toggleTokenBool.value){
              toggleTokenBool.value = true
              const route = useRoute();
              const token = useCookie("websiteAuthorization");
              token.value = null;
              ElMessage({ message: '登录已失效,请重新登录!'});
              navigateTo("/login?from=" + route.fullPath);     
            } 
          } else {
            //若需要报错提醒
            if (process.client && options.showError && res.msg) {
              ElMessage({ message: res.msg, customClass: "message-zindex" });
            }
            if (options.needReject) {
              resolve(res);
            }else{
              reject(res)
            }
          }
          }).catch((err) => {
            reject(err)
          })
        })
    }else{
      //路由中调用时
      return new Promise((resolve, reject) => {
        useFetch(url, { ...options}).then(({ data, error }) => {
          if (error.value) {
            reject(error.value)
            return
          }
          const res = data.value
          if (error.value) {
            reject(error.value);
            return;
          }
          const res = data.value;
          if (res.code == 200) {
            resolve(res);  
            const toggleTokenBool = useState('tokenBool')
            toggleTokenBool.value = false                
          } else if (res.code == 20001) {
            // token失效处理
            reject(res)
            const toggleTokenBool = useState('tokenBool')
            if(!toggleTokenBool.value){
              toggleTokenBool.value = true
              const route = useRoute();
              const token = useCookie("websiteAuthorization");
              token.value = null;
              ElMessage({ message: '登录已失效,请重新登录!'});
              navigateTo("/login?from=" + route.fullPath);     
            } 
          } else {
            //若需要报错提醒
            if (process.client && options.showError && res.msg) {
              ElMessage({ message: res.msg, customClass: "message-zindex" });
            }
            if (options.needReject) {
              resolve(res);
            }else{
              reject(res)
            }
          }
        }).catch((err) => {
          reject(err)
        })
      })
    }
}

// GET请求
export function useHttpGet(key,url,options = {}){
    options.method = "GET"
    return useHttp(key,url,options)
}

// POST请求
export function useHttpPost(key,url,options = {}){
    options.method = "POST"
    return useHttp(key,url,options)
}

状态管理(useState/Pinia)、cookie管理(useCookie)

我们可以在项目的根目录新建composables中创建状态管理文件如:composables/state.ts.

useState的使用

内容封装:

//首先引入useState、useCookie
import { useState, useCookie } from "nuxt/app";
//用户详情
export const useInfo = () =>
  useState("userData", () => {
    return {
      data: "",
    };
  });
//消息数量
export const messageNum = () =>
  useState("msgNum", () => {
    return {
      data: 0,
    };
  });
// token
export const useToken = () => useState("token",()=> "aaadd232cfdfdf23fdf") 

pinia的使用

pinia使用

cookie管理(useCookie)

// 获取 Cookie
let tokenCookies = useCookie('token')
// 设置 Cookie
tokenCookies .value = Cookies.value || ''
// 删除  Cookie
tokenCookies .value = undefined || null

token续期

什么是续期呢?为了用户安全,token会出现失效的状态,一般为1~30天。根据华为云等的做法,可以测试出,为保障用户安全,一般token有效期为2H,在1.5h时,后端会将新的token塞入响应头中,再取出替换。

useFetch(url, { 
        ...options,
        onResponse(ctx) {
          if(ctx.response.headers?.get('Authorizations')){
            const Authorization = useCookie("cookies名称");
            Authorization.value = ctx.response.headers?.get('Authorizations')
          }
        }
      })
$fetch(url, {
        ...options,
        onResponse(ctx) {
          if(ctx.response.headers?.get('Authorizations')){
            const Authorization = useCookie("cookies名称");
            Authorization.value = ctx.response.headers?.get('Authorizations')
          }
        }
      })
<think>好的,用户的问题是关于在Nuxt3中如何在服务端获取Cookie。我需要先回忆一下Nuxt3相关知识,特别是服务端处理Cookie的方法。根据之前的引用内容Nuxt2中可以通过asyncData的上下文对象来访问req和res,进而获取Cookie。但Nuxt3有了较大的变化,比如引入了useRequestHeaders和useCookie等Composables,所以需要确认这些新API的使用方式。 首先,用户可能在Nuxt3中遇到了服务端无法获取Cookie的问题,或者在服务端渲染时需要访问Cookie来获取用户状态。需要确保他们了解Nuxt3的服务端组件和客户端组件的区别,以及如何正确使用Composables来访问请求头中的Cookie信息。 接下来,要检查引用的资料,特别是引用2和引用4,其中提到了在服务端获取Cookie的方法,比如通过context.req.headers.cookie。但Nuxt3不再使用asyncData,而是改用useAsyncData和setup函数,或者服务器路由。需要将Nuxt2的方法迁移到Nuxt3的新API上。 然后,应该分步骤说明如何在Nuxt3中实现服务端获取Cookie。例如,在服务器API路由中使用useRequestHeaders来获取Cookie,或者在页面组件中使用useAsyncData结合useRequestHeaders。同时,需要提到第三方库如cookiecookie-parser来处理Cookie字符串,以及如何安全地处理Cookie数据,比如使用decodeURIComponent解码。 此外,需要注意process.server在Nuxt3中的使用是否仍然有效,或者是否有替代的环境检测方法。还需要强调Nuxt3useCookie的作用,它主要用于客户端管理Cookie,但服务端渲染时可能需要手动解析请求头。 最后,生成相关问题时要覆盖Nuxt3Cookie处理机制、客户端共享数据、安全注意事项以及替代Nuxt2的方法。确保回答结构清晰,步骤正确,并且提供代码示例帮助用户理解。</think>在 Nuxt3 中服务端获取 Cookie 主要通过以下两种方式实现,需结合服务端上下文和请求头处理: ### 一、服务端 API 路由获取 Cookie ```typescript // server/api/auth.get.ts import { parseCookies } from &#39;h3&#39; export default defineEventHandler((event) => { // 使用 useRequestHeaders 获取请求头 const headers = useRequestHeaders(event) // 解析 Cookie 字符串 const cookies = parseCookies(event) // 或直接访问 headers 对象 const rawCookie = headers.cookie // 获取特定 Cookie const token = cookies.token || getCookieFromString(&#39;token&#39;, rawCookie) return { status: &#39;authenticated&#39;, token } }) // 解析 Cookie 的辅助函数 function getCookieFromString(name: string, cookieString: string) { const cookieArr = cookieString?.split(&#39;;&#39;) || [] const cookie = cookieArr.find(c => c.trim().startsWith(`${name}=`)) return cookie ? decodeURIComponent(cookie.split(&#39;=&#39;)[1]) : null } ``` ### 、页面组件中获取 ```vue <script setup> // 服务端获取 const { data } = await useAsyncData(&#39;auth&#39;, async () => { const headers = useRequestHeaders([&#39;cookie&#39;]) const token = getCookieFromString(&#39;token&#39;, headers.cookie) return await $fetch(&#39;/api/user&#39;, { headers: { cookie: headers.cookie } }) }) // 客户端同步 const clientToken = useCookie(&#39;token&#39;) </script> ``` ### 关键点说明: 1. **请求头访问**:使用 `useRequestHeaders` 获取完整请求头,需在服务端上下文执行[^2][^4] 2. **Cookie 解析**:推荐使用 `h3` 的 `parseCookies` 或自行解析字符串 3. **编码处理**:注意使用 `decodeURIComponent` 处理编码后的值 4. **环境判断**:通过 `process.server` 判断执行环境[^2] 5. **安全策略**:在 `nuxt.config` 中配置 `runtimeConfig` 暴露所需请求头: ```javascript export default defineNuxtConfig({ runtimeConfig: { public: { cookieHeaders: [&#39;cookie&#39;] // 允许透传的请求头 } } }) ``` ### 注意事项: - 客户端首次访问时服务端渲染需确保 Cookie 同步到 Vuex/Pinia - 敏感信息应使用 HttpOnly Cookie 增强安全性 - 跨域场景需配置 CORS 和 `withCredentials`
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值