在 Nuxt3 使用 Axios 进行开发的时候遇到了跨域问题,查了 Nuxt3 的官方文档后得知需要使用 nitro  代理向后端请求数据,需要修改 nuxt.config.ts 文件,修改后的配置为:
| export default defineNuxtConfig({ | |
| pages: true, | |
| css: ["~/assets/css/main.css"], | |
|   postcss: { | |
|     plugins: { | |
| tailwindcss: {}, | |
| autoprefixer: {}, | |
|     }, | |
|   }, | |
| modules: ["nuxt-icon", "@pinia/nuxt", "@pinia-plugin-persistedstate/nuxt"], | |
| // devtools: { enabled: true }, | |
| // 跨域请求数据 | |
|   nitro: { | |
|     devProxy: { | |
| "/api/v1": { | |
| target: "http://localhost:44044/api/v1", | |
| changeOrigin: true, | |
|       }, | |
|     }, | |
|   }, | |
| }); | |
在我的 Nuxt3 中是将 Axios 配置成了插件的形式使用,安装 Axios: pnpm add axios ,安装安毕后在项目根目录的 plugins  文件夹中新建 axios.plugin.js  文件,这里我使用的是 JS 没有使用 TS(个人感觉在自己的小项目上使用 TS 会有多余类型负担), axios.plugin.js  文件内容如下:
| import axios from 'axios' | |
| // 引入自定义store | |
| import { useManagerStore } from '~/stores/managerGeneral.store' | |
| export default defineNuxtPlugin((NuxtApp) => { | |
| const instance = axios.create({ | |
| baseURL: '/api/v1', | |
| withCredentials: true, | |
| timeout: 3000 | |
|   }) | |
| // 添加请求拦截器 | |
| instance.interceptors.request.use( | |
| function (config) { | |
| // 在发送请求之前做些什么 | |
| if (useManagerStore().token) { | |
| config.headers.Authorization = `Bearer ${useManagerStore().token}`; | |
| } | |
|     return config; | |
|   }, | |
| function (error) { | |
| // 对请求错误做些什么 | |
| return Promise.reject(error); | |
| } | |
| ); | |
| // 添加响应拦截器 | |
| instance.interceptors.response.use( | |
| function (response) { | |
| // 2xx 范围内的状态码都会触发该函数。 | |
| // 对响应数据做点什么 | |
| if (response.status.toString().startsWith("2")) { | |
| return response.data; | |
| } | |
|     return response; | |
|   }, | |
| async function (error) { | |
| // 超出 2xx 范围的状态码都会触发该函数。 | |
| // 对响应错误做点什么 | |
| let originalRequest = error.config; | |
| if (error.response.data.error.statusCode === 401 && !originalRequest._retry && useManagerStore().token) { | |
| originalRequest._retry = true; | |
|       try { | |
| let result = await instance.post('/auth/refreshToken', { token: useManagerStore().token }) | |
| useManagerStore().token = result.access_token; | |
| originalRequest.headers.Authorization = `Bearer ${access_token}`; | |
| return instance(originalRequest); | |
| } catch (error) { | |
| // useManagerStore().token = null | |
| return Promise.reject(error); | |
| } | |
| } | |
| return Promise.reject(error.response.data.error); | |
| } | |
| ); | |
|   return { | |
|     provide: { | |
|       axios: instance | |
| } | |
| } | |
| }) | |
在上面的代码中,我对 axios 进行了简单的二次封装,在 axios 初始化时添加了根路径 /api/v1  这是因为我后端的路径中的地址后面是添加了 /api/v1  两个路径的,如果你的后端路径中没有可以直接修改为 / 。
还添加了请求拦截器和响应拦截器:
- 
请求拦截器中每次请求前会添加认证的 token 信息; 
- 
响应拦截器中添加了状态码识别,对 2 开头和 4 开头的状态码进行分别处理; 
在请求时添加的认证 token 是在自定义的 store 中获取的,我是使用 Pinia  进行状态管理,要在 Nuxt3 中使用 Pinia  的话我也是将它封装成了一个插件,具体如何操作之后再做演示。
在需要向后端请求数据的页面中需要在 useNuxtApp()  方法中解构出插件 $axios
| <script setup> | |
| const { $axios } = useNuxtApp() | |
| let data = ref(null) | |
| onMounted(async () => { | |
| data.value = await $axios.get('/') | |
| }) | |
| <script> | |
| <template> | |
|   {{ data }} | |
| <template> | |
这样使用 axios  优点是代码简单、直观,缺点是不方便,在每个需要请求的页面中都需要解构 $axios  插件。
其实在 Vue3 中有更好的写法,但我在 Nuxt3 中没有成功实现,应该是因为 Nuxt3 是约定大于配置的原因吧,在 Nuxt3 官方文档中是推荐使用自带的 useFetch  的,但我使用下来觉得太不方便,如果有技术大佬知道如何对 useFetch  进行二次封装的话,欢迎留言赐教,谢谢。
