| | |
| | | import { useUserStore } from "@/store" |
| | | import { getToken } from "@/utils/auth" |
| | | import { |
| | | useUserStore |
| | | } from "@/store" |
| | | import storage from "@/utils/storage" |
| | | import { showMessage } from "./status" |
| | | |
| | | // 重试队列,每一项将是一个待执行的函数形式 |
| | | let requestQueue = [] |
| | | import { |
| | | showMessage |
| | | } from "./status" |
| | | import website from '@/config/website' |
| | | import { |
| | | Base64 |
| | | } from 'js-base64' |
| | | |
| | | // 防止重复提交 |
| | | const repeatSubmit = config => { |
| | | const requestObj = { |
| | | url: config.url, |
| | | data: |
| | | typeof config.data === "object" |
| | | ? JSON.stringify(config.data) |
| | | : config.data, |
| | | data: typeof config.data === "object" ? |
| | | JSON.stringify(config.data) : config.data, |
| | | time: new Date().getTime() |
| | | } |
| | | const sessionObj = storage.getJSON("sessionObj") |
| | |
| | | } |
| | | } |
| | | |
| | | // 是否正在刷新token的标记 |
| | | let isRefreshing = false |
| | | // 请求拦截器 |
| | | function requestInterceptors(http) { |
| | | |
| | | // 刷新token |
| | | const refreshToken = async (http, config) => { |
| | | // 是否在获取token中,防止重复获取 |
| | | if (!isRefreshing) { |
| | | // 修改登录状态为true |
| | | isRefreshing = true |
| | | // 等待登录完成 |
| | | await useUserStore().authLogin() |
| | | // 登录完成之后,开始执行队列请求 |
| | | requestQueue.forEach(cb => cb()) |
| | | // 重试完了清空这个队列 |
| | | requestQueue = [] |
| | | isRefreshing = false |
| | | // 重新执行本次请求 |
| | | return http.request(config) |
| | | } |
| | | |
| | | return new Promise(resolve => { |
| | | // 将resolve放进队列,用一个函数形式来保存,等登录后直接执行 |
| | | requestQueue.push(() => { |
| | | resolve(http.request(config)) |
| | | }) |
| | | http.interceptors.request.use((config) => { |
| | | const {detail} = useUserStore().$state?.userInfo || {} |
| | | // 假设有token值需要在头部需要携带 |
| | | let accessToken = useUserStore()?.$state?.userInfo?.access_token; |
| | | if (accessToken) { |
| | | config.header['Blade-Auth'] = 'bearer ' + accessToken; |
| | | } |
| | | if (detail?.areaCode) { |
| | | config.header['areaCode'] = detail.areaCode |
| | | } |
| | | // 安全请求header |
| | | config.header['Blade-Requested-With'] = 'BladeHttpRequest'; |
| | | // 客户端认证参数 |
| | | config.header['Authorization'] = 'Basic ' + Base64.encode(website.clientId + ':' + website.clientSecret); |
| | | return config |
| | | }, config => { // 可使用async await 做异步操作 |
| | | return Promise.reject(config) |
| | | }) |
| | | } |
| | | |
| | | function requestInterceptors(http) { |
| | | /** |
| | | * 请求拦截 |
| | | * @param {object} http |
| | | */ |
| | | http.interceptors.request.use( |
| | | config => { |
| | | // 可使用async await 做异步操作 |
| | | // 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{} |
| | | config.data = config.data || {} |
| | | // 自定义参数 |
| | | const custom = config?.custom |
| | | |
| | | // 是否需要设置 token |
| | | const isToken = custom?.auth === false |
| | | if (getToken() && !isToken && config.header) { |
| | | // token设置 |
| | | config.header.token = getToken() |
| | | } |
| | | |
| | | // 是否显示 loading |
| | | if (custom?.loading) { |
| | | uni.showLoading({ |
| | | title: "加载中", |
| | | mask: true |
| | | }) |
| | | } |
| | | |
| | | // 是否需要防止数据重复提交 |
| | | const isRepeatSubmit = custom?.repeatSubmit === false |
| | | if ( |
| | | !isRepeatSubmit && |
| | | (config.method === "POST" || config.method === "UPLOAD") |
| | | ) { |
| | | repeatSubmit(config) |
| | | } |
| | | return config |
| | | }, |
| | | ( |
| | | config // 可使用async await 做异步操作 |
| | | ) => Promise.reject(config) |
| | | ) |
| | | } |
| | | // 响应拦截器 |
| | | function responseInterceptors(http) { |
| | | /** |
| | | * 响应拦截 |
| | | * @param {object} http |
| | | */ |
| | | http.interceptors.response.use( |
| | | response => { |
| | | /* 对响应成功做点什么 可使用async await 做异步操作 */ |
| | | const data = response.data |
| | | // 配置参数 |
| | | const config = response.config |
| | | // 自定义参数 |
| | | const custom = config?.custom |
| | | |
| | | // 登录状态失效,重新登录 |
| | | if (data.code === 401) { |
| | | return refreshToken(http, config) |
| | | } |
| | | |
| | | // 隐藏loading |
| | | if (custom?.loading) { |
| | | uni.hideLoading() |
| | | } |
| | | |
| | | // 请求成功则返回结果 |
| | | if (data.code === 200) { |
| | | return response || {} |
| | | } |
| | | |
| | | // 如果没有显式定义custom的toast参数为false的话,默认对报错进行toast弹出提示 |
| | | if (custom?.toast !== false) { |
| | | uni.$u.toast(data.message) |
| | | } |
| | | |
| | | // 请求失败则抛出错误 |
| | | return Promise.reject(data) |
| | | }, |
| | | response => { |
| | | // 自定义参数 |
| | | const custom = response.config?.custom |
| | | |
| | | // 隐藏loading |
| | | if (custom?.loading !== false) { |
| | | uni.hideLoading() |
| | | } |
| | | |
| | | // 如果没有显式定义custom的toast参数为false的话,默认对报错进行toast弹出提示 |
| | | if (custom?.toast !== false) { |
| | | const message = response.statusCode |
| | | ? showMessage(response.statusCode) |
| | | : "网络连接异常,请稍后再试!" |
| | | uni.$u.toast(message) |
| | | } |
| | | |
| | | return Promise.reject(response) |
| | | http.interceptors.response.use((response) => { |
| | | let res = response |
| | | const status = res.data.error_code || res.data.code || res.statusCode |
| | | const message = res?.data?.msg || res?.data?.error_description || res?.data?.message || '系统错误' |
| | | if (status !== 200) { |
| | | uni.showToast({title: message, icon: 'none'}); |
| | | return Promise.reject(response); |
| | | } |
| | | ) |
| | | return response; |
| | | }, (response) => { |
| | | /* 对响应错误做点什么 (statusCode !== 200)*/ |
| | | uni.showToast({title: response?.data?.msg, icon: 'none'}); |
| | | if (response.statusCode === 401) { |
| | | const pages = getCurrentPages() |
| | | const currentPage = pages[pages.length - 1] |
| | | uni.redirectTo({ |
| | | url: `/pages/login/index?redirect=/${currentPage.route}` |
| | | }) |
| | | } |
| | | return Promise.reject(response) |
| | | }) |
| | | } |
| | | |
| | | export { requestInterceptors, responseInterceptors } |
| | | export { |
| | | requestInterceptors, |
| | | responseInterceptors |
| | | } |