赞
踩
- # 项目src下新建utils/request.ts
- # npm i axios 是必须滴
- import axios from 'axios'
-
- const baseURL = 'https://ilovesh.com' // 基地址
- const instance = axios.create({
- baseURL,
- timeout: 3000 // 请求超时时间 (3秒超时)
- })
-
- export { baseURL, instance }
- // 添加请求拦截器
- instance.interceptors.request.use(
- function (config) {
- // 在发送请求之前做些什么
- return config
- },
- function (error) {
- // 对请求错误做些什么
- return Promise.reject(error)
- }
- )
-
- // 添加响应拦截器
- instance.interceptors.response.use(
- function (response) {
- // 2xx 范围内的状态码都会触发该函数。
- // 对响应数据做点什么
- return response
- },
- function (error) {
- // 超出 2xx 范围的状态码都会触发该函数。
- // 对响应错误做点什么
- return Promise.reject(error)
- }
- )

- // 把上图圈出的数据剥离出来
- // 修改响应拦截器的return值
- ...
- function (response) {
- // 2xx 范围内的状态码都会触发该函数。
- // 对响应数据做点什么
- return response.data
- }
- ...
-
笔者首先在 App.vue 里写了个测试用例,先拿到Token:
- import { instance } from '@/utils/request'
- import { useUserStore } from '@/stores'
-
- // pinia仓库
- const userStore = useUserStore()
-
- instance
- .post('/login/password', {
- mobile: '13230000001',
- password: 'abc12345'
- })
- .then((res) => {
- // 调用仓库里的自定义存储方法 (现在仓库里有Token了)
- userStore.updateUser(res.data)
- })

接下来修改axios实例的请求拦截器(在请求头里携带Token):
- instance.interceptors.request.use(
- function (config) {
- // 在发送请求之前做些什么
- // 获取Pinia仓库
- const userStore = useUserStore()
- const token = userStore.user?.token
- if (token) {
- config.headers.Authorization = `Bearer ${token}`
- }
- return config
- },
- function (error) {
- // 对请求错误做些什么
- return Promise.reject(error)
- }
- )
配置完成后,最好能找个需要Token才能访问的接口测试一下!
这里指的是响应是成功的(2xx 范围内的状态码),业务是失败的。笔者这里的业务逻辑成功与否根据code区分,code = 10000 成功,code !== 10000 失败

修改axios实例的响应拦截器:
- // 添加响应拦截器
- instance.interceptors.response.use(
- function (response) {
- // 2xx 范围内的状态码都会触发该函数
- // 对响应数据做点什么
- const { code, message } = response.data
- if (code !== 10000) return Toast(message) // 这里使用vant库的轻提示组件
- return response.data
- },
- function (error) {
- // 超出 2xx 范围的状态码都会触发该函数。
- // 对响应错误做点什么
- return Promise.reject(error)
- }
- )
状态码 401 Unauthorized 代表客户端错误,指的是由于缺乏目标资源要求的身份验证凭证,发送的请求未得到满足。说人话就是“Token失效/出错”!
为了尽可能追求完美,这里的逻辑比较复杂:
① Token失效,使用路由转回登录页
② 假设在 abc 页面访问,这里发现 Token 失效了,我们使用路由转回了登录页;
重新登录成功后,体验好的app会让我回到本来访问的abc页面,并且携带可能的路径参数;
③ 实现方式:把原本的页面路径&参数全部给到query带上,重新登录成功就能完美转回了;
如何获取原本页面的路径&参数?使用 router.currentRoute.value.fullpath
- // 响应拦截器失败的函数内修改
- function (error: AxiosError) {
- // 超出 2xx 范围的状态码都会触发该函数
- // 对响应错误做点什么
- if (error.response?.status === 401) {
- // Pinia里删除用户信息
- const userStore = useUserStore()
- userStore.delUser()
- // 跳转登录,带上接口失效所在页面的地址,登录完成后回跳使用
- router.push({
- path: '/login',
- query: { redirectURL: router.currentRoute.value.fullPath }
- })
- }
- return Promise.reject(error)
- }
- # 使用axios实例的伪代码
- instance({
- method: '',
- url: '',
- params / data (get请求的时候是params,get请求以外的是data)
- })
-
- # 希望封装一个函数,它的使用是 request<泛型>(url, method, 可能有/可能无的接口请求参数)
雏形大概长这样:
- import axios, { AxiosError, type Method } from 'axios'
-
- // 请求工具函数
- const request = (url: string, method: Method = 'get', requestParams?: object) => {
- return instance.request({
- url,
- method,
- [method.toLowerCase() === 'get' ? 'params' : 'data']: requestParams
- })
- }
-
- // 按需导出
- export { baseURL, instance, request }
加上泛型的最终版:
- // 这个需要替换 axios.request 默认的响应成功后的结果类型
- // 之前是:传 { name: string } 然后res是 res = { data: { name: string } }
- // 但现在:在响应拦截器中返回了 res.data 也就是将来响应成功后的结果,和上面的类型一致吗?
- // 所以要:request<数据类型,数据类型>() 这样才指定了 res.data 的类型
- // 但是呢:后台返回的数据结构相同,所以可以抽取相同的类型
- import axios, { AxiosError, type Method } from 'axios'
- type Data<T> = {
- // 内容根据接口返回的规则做修改
- code: number
- message: string
- data: T
- }
- // 请求工具函数
- const request = <T>(url: string, method: Method = 'get', requestParams?: object) => {
- return instance.request<T, Data<T>>({
- url,
- method,
- [method.toLowerCase() === 'get' ? 'params' : 'data']: requestParams
- })
- }
-
- // 按需导出
- export { baseURL, instance, request }
使用范例:
- import { request } from '@/utils/request'
- import type { User } from '@/types/user'
-
- request<User>('/login/password', 'post', {
- mobile: '13230000001',
- password: 'abc12345'
- }).then((res) => {
- // 调用仓库里的自定义存储方法
- userStore.updateUser(res.data)
- })
End-------------------
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。