| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- import type { UseFetchOptions } from '#app'
- import type { BasicResponse } from '~/models/common'
- import type { RequestQueueItem, IInterceptor, IConfig, IOption } from './interface'
- import { useLoginStore } from '~/stores/user/login'
- import { getToken, getRefreshToken } from '../auth'
- class Request {
- public baseURL: string
- public interceptor: IInterceptor
- private isRefreshing = false // 是否正在刷新token,开启请求队列
- private requestQueue: RequestQueueItem[] // 待请求队列
- constructor({ baseURL, interceptor }: IConfig) {
- this.baseURL = baseURL
- this.interceptor = interceptor as IInterceptor
- this.isRefreshing = false
- this.requestQueue = []
- }
- request<T = BasicResponse>({ url, method, params, data, options }: IOption<T>): Promise<T> {
- const newOptions: UseFetchOptions<T> = {
- baseURL: this.baseURL,
- method,
- query: params,
- body: data,
- ...options,
- onRequest: this.interceptor?.onRequest,
- onRequestError: this.interceptor?.onRequestError,
- onResponse: this.interceptor?.onResponse,
- onResponseError: this.interceptor?.onResponseError,
- }
- return new Promise((resolve, reject) => {
- this.requestPipeline(url, newOptions, resolve, reject)
- })
- }
- // 请求管道处理具体细节
- requestPipeline<T = BasicResponse>(
- url: string,
- options: UseFetchOptions<T>,
- resolve: (data: T) => void,
- reject: (data: unknown) => void
- ): void {
- const token = getToken()
- const newOptions = {
- ...options,
- headers: {
- Authorization: token ? `Bearer ${token}` : '',
- ...options?.headers,
- },
- }
- $fetch<T>(url, newOptions as any)
- .then((res) => {
- resolve(res as T)
- })
- .catch((error) => {
- if (error.status === 401) {
- if (!this.isRefreshing) {
- this.isRefreshing = true
- this.refreshToken()
- }
- this.addRequestQueueForRefreshToken<T>(url, options, resolve, reject)
- } else {
- reject(error)
- }
- })
- }
- // 刷新token
- refreshToken() {
- const loginStore = useLoginStore()
- this.postRefreshTokenFunc()
- .then((res) => {
- if (res.data) {
- const data = res.data
- loginStore.updateToken(data)
- this.requestQueueStartAfterRefreshToken()
- }
- })
- .catch(() => {
- loginStore.logout()
- navigateTo({ path: '/' })
- // ElMessage.error('登录已失效,需要重新登录')
- // navigateTo({ path: '/login' })
- })
- .finally(() => {
- this.isRefreshing = false
- })
- }
- postRefreshTokenFunc(): Promise<BasicResponse> {
- const data = {
- clientId: getCanvasFingerprint(),
- }
- const token = getRefreshToken()
- return $fetch(this.baseURL + '/auth/refresh', {
- method: 'post',
- body: data,
- headers: {
- Authorization: `Bearer ${token}`,
- 'Content-Type': 'application/json',
- },
- })
- }
- // 添加请求到等待队列
- addRequestQueueForRefreshToken<T = BasicResponse>(
- url: string,
- options: UseFetchOptions<T>,
- resolve: (data: T) => void,
- reject: (data: unknown) => void
- ): void {
- this.requestQueue.push({
- url,
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
- options,
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
- resolve,
- reject,
- })
- }
- // 刷新token成功等待队列开始请求
- requestQueueStartAfterRefreshToken(): void {
- let requestQueueItem = this.requestQueue.pop()
- while (requestQueueItem) {
- const { options, url, resolve, reject } = requestQueueItem
- this.requestPipeline(url, options, resolve, reject)
- requestQueueItem = this.requestQueue.pop()
- }
- }
- }
- export default Request
|