shuishen
2025-10-11 3fc27febccd04e2fcffbd2cdd16d2daafd0b3ca3
src/utils/request/interceptors.js
@@ -1,19 +1,21 @@
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")
@@ -38,134 +40,55 @@
  }
}
// 是否正在刷新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
}