| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- import Taro from '@tarojs/taro'
- import { hc } from 'hono/client'
- import ResponsePolyfill from './response-polyfill'
- // 刷新token的函数
- let isRefreshing = false
- let refreshSubscribers: ((token: string) => void)[] = []
- // 执行token刷新
- const refreshToken = async (): Promise<string | null> => {
- if (isRefreshing) {
- // 如果已经在刷新,等待结果
- return new Promise((resolve) => {
- refreshSubscribers.push((token) => {
- resolve(token)
- })
- })
- }
- isRefreshing = true
- try {
- const refreshToken = Taro.getStorageSync('enterprise_refresh_token')
- if (!refreshToken) {
- throw new Error('未找到刷新token')
- }
- // 调用刷新token接口
- const response = await Taro.request({
- url: `${process.env.TARO_APP_API_BASE_URL || 'http://localhost:3000'}/api/v1/yongren/auth/refresh-token`,
- method: 'POST',
- header: {
- 'Content-Type': 'application/json',
- 'Authorization': `Bearer ${refreshToken}`
- }
- })
- if (response.statusCode === 200) {
- const { token, refresh_token: newRefreshToken } = response.data
- Taro.setStorageSync('enterprise_token', token)
- if (newRefreshToken) {
- Taro.setStorageSync('enterprise_refresh_token', newRefreshToken)
- }
- // 通知所有等待的请求
- refreshSubscribers.forEach(callback => callback(token))
- refreshSubscribers = []
- return token
- } else {
- throw new Error('刷新token失败')
- }
- } catch (error) {
- console.error('刷新token失败:', error)
- // 清除token,跳转到登录页
- Taro.removeStorageSync('enterprise_token')
- Taro.removeStorageSync('enterprise_refresh_token')
- Taro.removeStorageSync('enterpriseUserInfo')
- // 跳转到登录页
- Taro.showToast({
- title: '登录已过期,请重新登录',
- icon: 'none'
- })
- setTimeout(() => {
- Taro.redirectTo({
- url: '/pages/login/index'
- })
- }, 1500)
- return null
- } finally {
- isRefreshing = false
- }
- }
- // API配置
- const API_BASE_URL = process.env.TARO_APP_API_BASE_URL || 'http://localhost:3000'
- // 完整的API地址
- // const BASE_URL = `${API_BASE_URL}/api/${API_VERSION}`
- // 创建自定义fetch函数,适配Taro.request,支持token自动刷新
- const taroFetch: any = async (input, init) => {
- const url = typeof input === 'string' ? input : input.url
- const method = init.method || 'GET'
- const requestHeaders: Record<string, string> = init.headers;
- const keyOfContentType = Object.keys(requestHeaders).find(item => item.toLowerCase() === 'content-type')
- if (!keyOfContentType) {
- requestHeaders['content-type'] = 'application/json'
- }
- // 构建Taro请求选项
- const options: Taro.request.Option = {
- url,
- method: method as any,
- data: init.body,
- header: requestHeaders
- }
- // 添加token - 优先使用企业token,兼容mini_token
- let token = Taro.getStorageSync('enterprise_token')
- if (!token) {
- token = Taro.getStorageSync('mini_token')
- }
- if (token) {
- options.header = {
- ...options.header,
- 'Authorization': `Bearer ${token}`
- }
- }
- // 发送请求
- const sendRequest = async (): Promise<any> => {
- try {
- console.log('API请求:', options.url)
- const response = await Taro.request(options)
- const responseHeaders = response.header;
- // 处理204 No Content响应,不设置body
- const body = response.statusCode === 204
- ? null
- : responseHeaders['content-type']!.includes('application/json')
- ? JSON.stringify(response.data)
- : response.data;
- return new ResponsePolyfill(
- body,
- {
- status: response.statusCode,
- statusText: response.errMsg || 'OK',
- headers: responseHeaders
- }
- )
- } catch (error) {
- console.error('API Error:', error)
- throw error
- }
- }
- try {
- let response = await sendRequest()
- // 检查是否为401错误,尝试刷新token
- if (response.status === 401 && token) {
- console.log('检测到401错误,尝试刷新token...')
- const newToken = await refreshToken()
- if (newToken) {
- // 更新请求header中的token
- options.header = {
- ...options.header,
- 'Authorization': `Bearer ${newToken}`
- }
- // 重试原始请求
- response = await sendRequest()
- } else {
- // 刷新失败,返回原始401响应
- return response
- }
- }
- return response
- } catch (error) {
- console.error('API请求失败:', error)
- Taro.showToast({
- title: error.message || '网络错误',
- icon: 'none'
- })
- throw error
- }
- }
- // 创建Hono RPC客户端
- export const rpcClient = <T extends any>() => {
- // @ts-ignore
- return hc<T>(`${API_BASE_URL}`, {
- fetch: taroFetch
- })
- }
|