Skip to content

Commit

Permalink
feat: support matcher for interceptor
Browse files Browse the repository at this point in the history
  • Loading branch information
haoziqaq committed Dec 2, 2023
1 parent 57fc9a4 commit f58a7df
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 19 deletions.
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,19 @@
"scripts": {
"bootstrap": "pnpm i && pnpm build && pnpm --filter ./playground i",
"dev": "tsc -w",
"dev:play": "pnpm --dir ./playground dev",
"build": "rimraf ./es && tsc",
"release": "pnpm build && vr release"
},
"dependencies": {
"@varlet/shared": "^2.19.2",
"axios": "^1.4.0",
"micromatch": "^4.0.5",
"minimatch": "^9.0.3",
"qs": "^6.11.0"
},
"devDependencies": {
"@types/minimatch": "^5.1.2",
"@types/qs": "^6.9.7",
"@varlet/release": "0.0.3",
"rimraf": "^5.0.1",
Expand Down
10 changes: 5 additions & 5 deletions playground/src/request/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ const useAxle = createUseAxle({
onTransform: (response) => response.data,
})

axle.axios.interceptors.response.use(
(response) => {
axle.useResponseInterceptor({
onFulfilled(response) {
if (response.data.code !== 200 && response.data.message) {
Snackbar.warning(response.data.message)
}

return response.data
},
(error) => {
onRejected(error) {
console.log(error)
Snackbar.error(error.message)
return Promise.reject(error)
}
)
},
})

export { axle, useAxle }
30 changes: 17 additions & 13 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions src/interceptors/requestHeadersInterceptor.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import { isFunction } from '@varlet/shared'
import { createMatcher } from '../matcher'
import type { RequestInterceptor } from '../instance'
import type { AxiosInterceptorOptions } from 'axios'

export interface RequestHeadersInterceptorOptions {
headers?: Record<string, string> | (() => Record<string, string>)
axiosInterceptorOptions?: AxiosInterceptorOptions
include?: string[]
exclude?: string[]
}

export function requestHeadersInterceptor(options: RequestHeadersInterceptorOptions = {}): RequestInterceptor {
const { headers: headersOrGetter } = options

return {
onFulfilled(config) {
const matcher = createMatcher(options.include, options.exclude)
if (!matcher(config.method ?? '', config.url ?? '')) {
return config
}

const headers = (isFunction(headersOrGetter) ? headersOrGetter() : headersOrGetter) ?? {}

Object.entries(headers).forEach(([key, value]) => {
Expand Down
8 changes: 8 additions & 0 deletions src/interceptors/responseBlobInterceptor.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import type { AxiosInterceptorOptions, AxiosResponse } from 'axios'
import type { ResponseInterceptor } from '../instance'
import { createMatcher } from '../matcher'

export interface ResponseBlobInterceptorOptions {
onResponse?: (response: AxiosResponse<any, any>) => any
axiosInterceptorOptions?: AxiosInterceptorOptions
include?: string[]
exclude?: string[]
}

export function responseBlobInterceptor(options: ResponseBlobInterceptorOptions = {}): ResponseInterceptor {
return {
onFulfilled(response) {
const matcher = createMatcher(options.include, options.exclude)
if (!matcher(response.config.method ?? '', response.config.url ?? '')) {
return response
}

if (response.request.responseType === 'blob') {
return options.onResponse?.(response) ?? response
}
Expand Down
11 changes: 10 additions & 1 deletion src/interceptors/responseTimeoutInterceptor.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import type { AxiosInterceptorOptions, AxiosResponse } from 'axios'
import type { AxiosInterceptorOptions } from 'axios'
import type { ResponseInterceptor } from '../instance'
import { createMatcher } from '../matcher'

export interface ResponseTimeoutInterceptorOptions {
normalizeErrorCode?: string
axiosInterceptorOptions?: AxiosInterceptorOptions
include?: string[]
exclude?: string[]
}

export function responseTimeoutInterceptor(options: ResponseTimeoutInterceptorOptions = {}): ResponseInterceptor {
Expand All @@ -12,6 +15,12 @@ export function responseTimeoutInterceptor(options: ResponseTimeoutInterceptorOp
return response
},
onRejected(error) {
const matcher = createMatcher(options.include, options.exclude)

if (!matcher(error.config.method ?? '', error.config.url ?? '')) {
return Promise.reject(error)
}

if ((error.code == 'ECONNABORTED' && error.message.includes('timeout')) || error.code === 'ETIMEDOUT') {
error.code = options?.normalizeErrorCode ?? 'TIMEOUT'
}
Expand Down
33 changes: 33 additions & 0 deletions src/matcher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { minimatch } from 'minimatch'

export function matchPattern(pattern: string, method: string, url: string) {
if (pattern.startsWith('method:')) {
return pattern.replace('method:', '').trim() === method
} else {
return minimatch(url ?? '', pattern)
}
}

export function createMatcher(include?: string[], exclude?: string[]) {
function matcher(method: string, url: string) {
if (!include && !exclude) {
return true
}

const isExclude = (exclude ?? []).some((pattern) => matchPattern(pattern, method, url))

if (isExclude) {
return false
}

if (!include) {
return true
}

const isInclude = (include ?? []).some((pattern) => matchPattern(pattern, method, url))

return isInclude
}

return matcher
}

0 comments on commit f58a7df

Please sign in to comment.