fix: 错误处理不是每次出错都执行
parent
78eaec150d
commit
fb4762d01a
|
@ -172,7 +172,7 @@
|
|||
|
||||
.custom-block {
|
||||
border-radius: 6px;
|
||||
background-color: var(--vp-custom-block-tip-bg);
|
||||
background-color: var(--vp-custom-block-tip-bg) !important;
|
||||
}
|
||||
|
||||
.dark .DocSearch-Modal {
|
||||
|
|
|
@ -88,7 +88,7 @@ axios.interceptors.response.eject(ejectId);
|
|||
```ts
|
||||
import axios from 'axios-miniprogram';
|
||||
|
||||
axios.interceptors.request.use(
|
||||
axios.interceptors.response.use(
|
||||
function (response) {
|
||||
// 在 then 之前做些什么
|
||||
return response;
|
||||
|
@ -99,7 +99,7 @@ axios.interceptors.request.use(
|
|||
},
|
||||
);
|
||||
|
||||
axios.interceptors.request.use(
|
||||
axios.interceptors.response.use(
|
||||
function (response) {
|
||||
// 在 then 之前做些什么
|
||||
return response;
|
||||
|
@ -111,5 +111,5 @@ axios.interceptors.request.use(
|
|||
);
|
||||
|
||||
// 移除所有响应拦截器
|
||||
axios.interceptors.request.clear();
|
||||
axios.interceptors.response.clear();
|
||||
```
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { buildURL } from '../helpers/buildURL';
|
||||
import { isAbsoluteURL } from '../helpers/isAbsoluteURL';
|
||||
import { combineURL } from '../helpers/combineURL';
|
||||
import { isString } from '../helpers/isTypes';
|
||||
import { isFunction, isPromise, isString } from '../helpers/isTypes';
|
||||
import {
|
||||
AxiosAdapter,
|
||||
AxiosAdapterRequestMethod,
|
||||
|
@ -274,6 +274,20 @@ export default class Axios extends AxiosDomain {
|
|||
);
|
||||
}
|
||||
|
||||
// 错误处理
|
||||
next = next.catch((reason) => {
|
||||
const { errorHandler } = config;
|
||||
|
||||
if (isFunction(errorHandler)) {
|
||||
const promise = errorHandler(reason);
|
||||
if (isPromise(promise)) {
|
||||
return promise.then(() => Promise.reject(reason));
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.reject(reason);
|
||||
});
|
||||
|
||||
return next as Promise<AxiosResponse>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { isFunction, isPromise, isString } from '../helpers/isTypes';
|
||||
import { isFunction, isString } from '../helpers/isTypes';
|
||||
import { assert } from '../helpers/error';
|
||||
import { Cancel, isCancel, isCancelToken } from './cancel';
|
||||
import { flattenHeaders } from './flattenHeaders';
|
||||
|
@ -22,47 +22,35 @@ export function dispatchRequest(config: AxiosRequestConfig) {
|
|||
assert(isString(config.url), 'url 不是一个 string');
|
||||
assert(isString(config.method), 'method 不是一个 string');
|
||||
|
||||
const { errorHandler, transformRequest, transformResponse } = config;
|
||||
|
||||
config.url = transformURL(config);
|
||||
config.headers = flattenHeaders(config);
|
||||
|
||||
if (withDataRE.test(config.method!)) {
|
||||
transformer(config, transformRequest);
|
||||
transformer(config, config.transformRequest);
|
||||
}
|
||||
|
||||
function onSuccess(response: AxiosResponse) {
|
||||
throwIfCancellationRequested(config);
|
||||
transformer(response, transformResponse);
|
||||
transformer(response, config.transformResponse);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
function onError(reason: Cancel | AxiosErrorResponse) {
|
||||
if (!isCancel(reason)) {
|
||||
throwIfCancellationRequested(config);
|
||||
transformer(reason.response, transformResponse);
|
||||
}
|
||||
|
||||
if (isFunction(errorHandler)) {
|
||||
const promise = errorHandler(reason);
|
||||
if (isPromise(promise)) {
|
||||
return promise.then(() => Promise.reject(reason));
|
||||
}
|
||||
transformer(reason.response, config.transformResponse);
|
||||
}
|
||||
|
||||
return Promise.reject(reason);
|
||||
}
|
||||
|
||||
function transformer<TData = unknown>(
|
||||
targetObject: { data?: TData; headers?: AnyObject },
|
||||
transformer?: AxiosTransformer<TData>,
|
||||
target: { data?: TData; headers?: AnyObject },
|
||||
fn?: AxiosTransformer<TData>,
|
||||
) {
|
||||
targetObject.data = transformData(
|
||||
targetObject.data,
|
||||
targetObject.headers,
|
||||
transformer,
|
||||
);
|
||||
target.data = transformData(target.data, target.headers, fn);
|
||||
}
|
||||
|
||||
return request(config).then(onSuccess).catch(onError);
|
||||
return request(config).then(onSuccess, onError);
|
||||
}
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
import { describe, test, expect, vi } from 'vitest';
|
||||
import { mockAdapter } from 'scripts/test.utils';
|
||||
import Axios from '@/core/Axios';
|
||||
import {
|
||||
mockAdapter,
|
||||
mockAdapterError,
|
||||
mockAdapterFail,
|
||||
} from 'scripts/test.utils';
|
||||
import AxiosDomain from '@/core/AxiosDomain';
|
||||
import Axios from '@/core/Axios';
|
||||
import axios from '@/axios';
|
||||
|
||||
describe('src/core/Axios.ts', () => {
|
||||
const data = {
|
||||
result: null,
|
||||
};
|
||||
const axios = new Axios({
|
||||
const axiosObj = new Axios({
|
||||
baseURL: 'http://api.com',
|
||||
});
|
||||
|
||||
|
@ -26,14 +31,14 @@ describe('src/core/Axios.ts', () => {
|
|||
baseURL: 'http://api.com',
|
||||
};
|
||||
|
||||
expect(axios.defaults).toEqual(c);
|
||||
expect(axios.interceptors).toBeTypeOf('object');
|
||||
expect(axios.request).toBeTypeOf('function');
|
||||
expect(axios.getUri).toBeTypeOf('function');
|
||||
expect(axios.fork).toBeTypeOf('function');
|
||||
expect(axiosObj.defaults).toEqual(c);
|
||||
expect(axiosObj.interceptors).toBeTypeOf('object');
|
||||
expect(axiosObj.request).toBeTypeOf('function');
|
||||
expect(axiosObj.getUri).toBeTypeOf('function');
|
||||
expect(axiosObj.fork).toBeTypeOf('function');
|
||||
|
||||
[...Axios.as, ...Axios.asp, ...Axios.asd].forEach((k) => {
|
||||
expect(axios[k]).toBeTypeOf('function');
|
||||
expect(axiosObj[k]).toBeTypeOf('function');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -48,7 +53,7 @@ describe('src/core/Axios.ts', () => {
|
|||
};
|
||||
|
||||
Axios.as.forEach((a) => {
|
||||
axios[a]('test', c).then((res) => {
|
||||
axiosObj[a]('test', c).then((res) => {
|
||||
expect(res.data).toEqual(data);
|
||||
});
|
||||
});
|
||||
|
@ -76,10 +81,10 @@ describe('src/core/Axios.ts', () => {
|
|||
};
|
||||
|
||||
Axios.asp.forEach((a) => {
|
||||
axios[a]('test', p, c1).then((res) => {
|
||||
axiosObj[a]('test', p, c1).then((res) => {
|
||||
expect(res.data).toEqual(data);
|
||||
});
|
||||
axios[a]('test/:id', { ...p }, c2).then((res) => {
|
||||
axiosObj[a]('test/:id', { ...p }, c2).then((res) => {
|
||||
expect(res.data).toEqual(data);
|
||||
});
|
||||
});
|
||||
|
@ -107,33 +112,99 @@ describe('src/core/Axios.ts', () => {
|
|||
};
|
||||
|
||||
Axios.asd.forEach((a) => {
|
||||
axios[a]('test', d, c1).then((res) => {
|
||||
axiosObj[a]('test', d, c1).then((res) => {
|
||||
expect(res.data).toEqual(data);
|
||||
});
|
||||
axios[a]('test/:id', d, c2).then((res) => {
|
||||
axiosObj[a]('test/:id', d, c2).then((res) => {
|
||||
expect(res.data).toEqual(data);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('应该支持错误处理', async () => {
|
||||
const e1 = vi.fn();
|
||||
const e2 = vi.fn();
|
||||
const c1 = {
|
||||
adapter: mockAdapterError(),
|
||||
url: 'test',
|
||||
errorHandler: e1,
|
||||
};
|
||||
const c2 = {
|
||||
adapter: mockAdapterFail(),
|
||||
url: 'test',
|
||||
errorHandler: e2,
|
||||
};
|
||||
|
||||
try {
|
||||
await axiosObj.request(c1);
|
||||
} catch (err) {
|
||||
expect(e1).toBeCalled();
|
||||
expect(e1.mock.calls[0][0]).toBe(err);
|
||||
expect(axios.isAxiosError(err)).toBeTruthy();
|
||||
}
|
||||
|
||||
try {
|
||||
await axiosObj.request(c2);
|
||||
} catch (err) {
|
||||
expect(e2).toBeCalled();
|
||||
expect(e2.mock.calls[0][0]).toBe(err);
|
||||
expect(axios.isAxiosError(err)).toBeTruthy();
|
||||
}
|
||||
});
|
||||
|
||||
test('应该支持异步错误处理', async () => {
|
||||
const e1 = vi.fn();
|
||||
const e2 = vi.fn();
|
||||
const c1 = {
|
||||
adapter: mockAdapterError(),
|
||||
url: 'test',
|
||||
errorHandler: async (err: unknown) => {
|
||||
e1(err);
|
||||
},
|
||||
};
|
||||
const c2 = {
|
||||
adapter: mockAdapterFail(),
|
||||
url: 'test',
|
||||
errorHandler: async (err: unknown) => {
|
||||
e2(err);
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
await axiosObj.request(c1);
|
||||
} catch (err) {
|
||||
expect(e1).toBeCalled();
|
||||
expect(e1.mock.calls[0][0]).toBe(err);
|
||||
expect(axios.isAxiosError(err)).toBeTruthy();
|
||||
}
|
||||
|
||||
try {
|
||||
await axiosObj.request(c2);
|
||||
} catch (err) {
|
||||
expect(e2).toBeCalled();
|
||||
expect(e2.mock.calls[0][0]).toBe(err);
|
||||
expect(axios.isAxiosError(err)).toBeTruthy();
|
||||
}
|
||||
});
|
||||
|
||||
test('应该支持添加/移除请求拦截器', async () => {
|
||||
const cb = vi.fn((v) => v);
|
||||
|
||||
const id = axios.interceptors.request.use(cb);
|
||||
await axios.request('/test', {
|
||||
const id = axiosObj.interceptors.request.use(cb);
|
||||
await axiosObj.request('/test', {
|
||||
adapter: mockAdapter(),
|
||||
});
|
||||
|
||||
expect(cb.mock.calls.length).toBe(1);
|
||||
|
||||
await axios.request('/test', {
|
||||
await axiosObj.request('/test', {
|
||||
adapter: mockAdapter(),
|
||||
});
|
||||
|
||||
expect(cb.mock.calls.length).toBe(2);
|
||||
|
||||
axios.interceptors.request.eject(id);
|
||||
await axios.request('/test', {
|
||||
axiosObj.interceptors.request.eject(id);
|
||||
await axiosObj.request('/test', {
|
||||
adapter: mockAdapter(),
|
||||
});
|
||||
|
||||
|
@ -141,7 +212,7 @@ describe('src/core/Axios.ts', () => {
|
|||
});
|
||||
|
||||
test('添加多个请求拦截器时应该按添加顺序从后往前依次执行', () => {
|
||||
const axios = new Axios();
|
||||
const axiosObj = new Axios();
|
||||
|
||||
const cb1 = vi.fn((v) => {
|
||||
expect(v.params.index).toBe(2);
|
||||
|
@ -159,11 +230,11 @@ describe('src/core/Axios.ts', () => {
|
|||
return v;
|
||||
});
|
||||
|
||||
axios.interceptors.request.use(cb1);
|
||||
axios.interceptors.request.use(cb2);
|
||||
axios.interceptors.request.use(cb3);
|
||||
axiosObj.interceptors.request.use(cb1);
|
||||
axiosObj.interceptors.request.use(cb2);
|
||||
axiosObj.interceptors.request.use(cb3);
|
||||
|
||||
axios.request('/test', {
|
||||
axiosObj.request('/test', {
|
||||
adapter: (config) => {
|
||||
expect(config.params!.index).toBe(3);
|
||||
},
|
||||
|
@ -174,7 +245,7 @@ describe('src/core/Axios.ts', () => {
|
|||
});
|
||||
|
||||
test('请求拦截器应该支持抛出异常', async () => {
|
||||
const axios = new Axios();
|
||||
const axiosObj = new Axios();
|
||||
const c = { adapter: vi.fn(), url: 'test' };
|
||||
const body = (v: any) => {
|
||||
throw { ...v, throw: true };
|
||||
|
@ -184,11 +255,11 @@ describe('src/core/Axios.ts', () => {
|
|||
const res2 = vi.fn(body);
|
||||
const rej2 = vi.fn(body);
|
||||
|
||||
axios.interceptors.request.use(res1, rej1);
|
||||
axios.interceptors.request.use(res2, rej2);
|
||||
axiosObj.interceptors.request.use(res1, rej1);
|
||||
axiosObj.interceptors.request.use(res2, rej2);
|
||||
|
||||
try {
|
||||
await axios.request(c);
|
||||
await axiosObj.request(c);
|
||||
} catch (err) {
|
||||
expect(err).toEqual({ ...c, throw: true });
|
||||
}
|
||||
|
@ -205,21 +276,21 @@ describe('src/core/Axios.ts', () => {
|
|||
test('应该支持添加/移除响应拦截器', async () => {
|
||||
const cb = vi.fn((v) => v);
|
||||
|
||||
const id = axios.interceptors.response.use(cb);
|
||||
await axios.request('/test', {
|
||||
const id = axiosObj.interceptors.response.use(cb);
|
||||
await axiosObj.request('/test', {
|
||||
adapter: mockAdapter(),
|
||||
});
|
||||
|
||||
expect(cb.mock.calls.length).toBe(1);
|
||||
|
||||
await axios.request('/test', {
|
||||
await axiosObj.request('/test', {
|
||||
adapter: mockAdapter(),
|
||||
});
|
||||
|
||||
expect(cb.mock.calls.length).toBe(2);
|
||||
|
||||
axios.interceptors.response.eject(id);
|
||||
await axios.request('/test', {
|
||||
axiosObj.interceptors.response.eject(id);
|
||||
await axiosObj.request('/test', {
|
||||
adapter: mockAdapter(),
|
||||
});
|
||||
|
||||
|
@ -227,7 +298,7 @@ describe('src/core/Axios.ts', () => {
|
|||
});
|
||||
|
||||
test('添加多个响应拦截器时应该按添加顺序从前往后依次执行', async () => {
|
||||
const axios = new Axios();
|
||||
const axiosObj = new Axios();
|
||||
|
||||
const cb1 = vi.fn((v) => {
|
||||
expect(v.data.index).toBe(0);
|
||||
|
@ -245,11 +316,11 @@ describe('src/core/Axios.ts', () => {
|
|||
return v;
|
||||
});
|
||||
|
||||
axios.interceptors.response.use(cb1);
|
||||
axios.interceptors.response.use(cb2);
|
||||
axios.interceptors.response.use(cb3);
|
||||
axiosObj.interceptors.response.use(cb1);
|
||||
axiosObj.interceptors.response.use(cb2);
|
||||
axiosObj.interceptors.response.use(cb3);
|
||||
|
||||
const response = await axios.request<{ index: 0 }>('/test', {
|
||||
const response = await axiosObj.request<{ index: 0 }>('/test', {
|
||||
adapter: mockAdapter({ data: { index: 0 } }),
|
||||
});
|
||||
|
||||
|
@ -257,7 +328,7 @@ describe('src/core/Axios.ts', () => {
|
|||
});
|
||||
|
||||
test('响应拦截器应该支持抛出异常', async () => {
|
||||
const axios = new Axios();
|
||||
const axiosObj = new Axios();
|
||||
const c = { adapter: vi.fn(mockAdapter()), url: 'test' };
|
||||
const body = () => {
|
||||
throw { throw: true };
|
||||
|
@ -267,11 +338,11 @@ describe('src/core/Axios.ts', () => {
|
|||
const res2 = vi.fn(body);
|
||||
const rej2 = vi.fn(body);
|
||||
|
||||
axios.interceptors.response.use(res1, rej1);
|
||||
axios.interceptors.response.use(res2, rej2);
|
||||
axiosObj.interceptors.response.use(res1, rej1);
|
||||
axiosObj.interceptors.response.use(res2, rej2);
|
||||
|
||||
try {
|
||||
await axios.request(c);
|
||||
await axiosObj.request(c);
|
||||
} catch (err) {
|
||||
expect(err).toEqual({ throw: true });
|
||||
}
|
||||
|
@ -283,22 +354,24 @@ describe('src/core/Axios.ts', () => {
|
|||
});
|
||||
|
||||
test('应该可以获取 URI', () => {
|
||||
expect(axios.getUri({ url: 'test' })).toBe('test');
|
||||
expect(axios.getUri({ url: 'test', params: { id: 1 } })).toBe('test?id=1');
|
||||
expect(axios.getUri({ url: 'test', paramsSerializer: () => 'id=1' })).toBe(
|
||||
expect(axiosObj.getUri({ url: 'test' })).toBe('test');
|
||||
expect(axiosObj.getUri({ url: 'test', params: { id: 1 } })).toBe(
|
||||
'test?id=1',
|
||||
);
|
||||
expect(
|
||||
axiosObj.getUri({ url: 'test', paramsSerializer: () => 'id=1' }),
|
||||
).toBe('test?id=1');
|
||||
});
|
||||
|
||||
test('派生的领域应该为 AxiosDomain 的实例', () => {
|
||||
expect(axios.fork() instanceof AxiosDomain).toBeTruthy();
|
||||
expect(axiosObj.fork() instanceof AxiosDomain).toBeTruthy();
|
||||
});
|
||||
|
||||
test('应该支持 绝对路径/相对路径 派生领域', () => {
|
||||
const a1 = axios.fork({ baseURL: 'test' });
|
||||
const a1 = axiosObj.fork({ baseURL: 'test' });
|
||||
const a2 = new Axios().fork({ baseURL: 'test' });
|
||||
const a3 = axios.fork({ baseURL: 'https://api.com' });
|
||||
const a4 = axios.fork();
|
||||
const a3 = axiosObj.fork({ baseURL: 'https://api.com' });
|
||||
const a4 = axiosObj.fork();
|
||||
|
||||
expect(a1.defaults.baseURL).toBe('http://api.com/test');
|
||||
expect(a2.defaults.baseURL).toBe('/test');
|
||||
|
@ -307,14 +380,14 @@ describe('src/core/Axios.ts', () => {
|
|||
});
|
||||
|
||||
test('派生自当前实例的领域应该可以复用当前实例的拦截器', async () => {
|
||||
const axios = new Axios();
|
||||
const axiosObj = new Axios();
|
||||
const req = vi.fn((v) => v);
|
||||
const res = vi.fn((v) => v);
|
||||
|
||||
axios.interceptors.request.use(req);
|
||||
axios.interceptors.response.use(res);
|
||||
axiosObj.interceptors.request.use(req);
|
||||
axiosObj.interceptors.response.use(res);
|
||||
|
||||
const a = axios.fork({ baseURL: 'test' });
|
||||
const a = axiosObj.fork({ baseURL: 'test' });
|
||||
await a.request('test', { adapter: mockAdapter() });
|
||||
|
||||
expect(req).toBeCalled();
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
import { describe, test, expect, vi } from 'vitest';
|
||||
import {
|
||||
asyncNext,
|
||||
mockAdapter,
|
||||
mockAdapterError,
|
||||
mockAdapterFail,
|
||||
} from 'scripts/test.utils';
|
||||
import { asyncNext, mockAdapter } from 'scripts/test.utils';
|
||||
import Axios from '@/core/Axios';
|
||||
import { dispatchRequest } from '@/core/dispatchRequest';
|
||||
import axios from '@/axios';
|
||||
|
@ -154,76 +149,6 @@ describe('src/core/dispatchRequest.ts', () => {
|
|||
expect(r.data).toEqual({ result: 1 });
|
||||
});
|
||||
|
||||
test('应该支持错误处理', async () => {
|
||||
const e1 = vi.fn();
|
||||
const e2 = vi.fn();
|
||||
const c1 = {
|
||||
...defaults,
|
||||
adapter: mockAdapterError(),
|
||||
url: 'test',
|
||||
errorHandler: e1,
|
||||
};
|
||||
const c2 = {
|
||||
...defaults,
|
||||
adapter: mockAdapterFail(),
|
||||
url: 'test',
|
||||
errorHandler: e2,
|
||||
};
|
||||
|
||||
try {
|
||||
await dispatchRequest(c1);
|
||||
} catch (err) {
|
||||
expect(e1).toBeCalled();
|
||||
expect(e1.mock.calls[0][0]).toBe(err);
|
||||
expect(axios.isAxiosError(err)).toBeTruthy();
|
||||
}
|
||||
|
||||
try {
|
||||
await dispatchRequest(c2);
|
||||
} catch (err) {
|
||||
expect(e2).toBeCalled();
|
||||
expect(e2.mock.calls[0][0]).toBe(err);
|
||||
expect(axios.isAxiosError(err)).toBeTruthy();
|
||||
}
|
||||
});
|
||||
|
||||
test('应该支持异步错误处理', async () => {
|
||||
const e1 = vi.fn();
|
||||
const e2 = vi.fn();
|
||||
const c1 = {
|
||||
...defaults,
|
||||
adapter: mockAdapterError(),
|
||||
url: 'test',
|
||||
errorHandler: async (err: unknown) => {
|
||||
e1(err);
|
||||
},
|
||||
};
|
||||
const c2 = {
|
||||
...defaults,
|
||||
adapter: mockAdapterFail(),
|
||||
url: 'test',
|
||||
errorHandler: async (err: unknown) => {
|
||||
e2(err);
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
await dispatchRequest(c1);
|
||||
} catch (err) {
|
||||
expect(e1).toBeCalled();
|
||||
expect(e1.mock.calls[0][0]).toBe(err);
|
||||
expect(axios.isAxiosError(err)).toBeTruthy();
|
||||
}
|
||||
|
||||
try {
|
||||
await dispatchRequest(c2);
|
||||
} catch (err) {
|
||||
expect(e2).toBeCalled();
|
||||
expect(e2.mock.calls[0][0]).toBe(err);
|
||||
expect(axios.isAxiosError(err)).toBeTruthy();
|
||||
}
|
||||
});
|
||||
|
||||
test('请求发送前取消请求应该抛出异常', async () => {
|
||||
const cb = vi.fn();
|
||||
const { cancel, token } = axios.CancelToken.source();
|
||||
|
|
Loading…
Reference in New Issue