refactor: 重构 request 提高可读性

pull/41/head
zjx0905 2023-04-07 13:50:08 +08:00
parent 3d137333e0
commit 40f1f77d46
5 changed files with 46 additions and 42 deletions

View File

@ -139,9 +139,9 @@ export interface AxiosRequestConfig
*/ */
transformResponse?: AxiosTransformer | AxiosTransformer[]; transformResponse?: AxiosTransformer | AxiosTransformer[];
/** /**
* *
*/ */
errorHandler?: (error: unknown) => Promise<unknown>; errorHandler?: (error: unknown) => Promise<AxiosResponse>;
/** /**
* *
*/ */

View File

@ -1,6 +1,7 @@
import { isFunction } from '../helpers/isTypes';
import { isCancel, isCancelToken } from './cancel'; import { isCancel, isCancelToken } from './cancel';
import { flattenHeaders } from './flattenHeaders'; import { flattenHeaders } from './flattenHeaders';
import { transformData } from './transformData'; import { AxiosTransformer, transformData } from './transformData';
import { request } from './request'; import { request } from './request';
import { AxiosRequestConfig, AxiosResponse } from './Axios'; import { AxiosRequestConfig, AxiosResponse } from './Axios';
import { transformURL } from './transformURL'; import { transformURL } from './transformURL';
@ -17,37 +18,45 @@ export default function dispatchRequest<TData = unknown>(
config: AxiosRequestConfig, config: AxiosRequestConfig,
): Promise<AxiosResponse> { ): Promise<AxiosResponse> {
throwIfCancellationRequested(config); throwIfCancellationRequested(config);
const { transformRequest, transformResponse } = config;
config.method = config.method ?? 'get';
config.url = transformURL(config); config.url = transformURL(config);
config.method = config.method ?? 'get';
config.headers = flattenHeaders(config); config.headers = flattenHeaders(config);
config.data = transformData(
config.data,
config.headers,
config.transformRequest,
);
function transformer(response: AxiosResponse<TData>) { transform(config, transformRequest);
response.data = transformData(
response.data as AnyObject, function onSuccess(response: AxiosResponse<TData>) {
response.headers, throwIfCancellationRequested(config);
config.transformResponse, transform(response, transformResponse);
return response;
}
function onError(reason: unknown) {
if (!isCancel(reason)) {
throwIfCancellationRequested(config);
if (isAxiosError(reason)) {
transform(reason.response as AxiosResponse<TData>, transformResponse);
}
}
if (isFunction(config.errorHandler)) {
return config.errorHandler(reason);
}
return Promise.reject(reason);
}
function transform<TData = unknown>(
target: AxiosRequestConfig | AxiosResponse<TData>,
transformer?: AxiosTransformer | AxiosTransformer[],
) {
target.data = transformData(
target.data as AnyObject,
target.headers,
transformer,
) as TData; ) as TData;
} }
return request<TData>(config) return request<TData>(config).then(onSuccess).catch(onError);
.then((response: AxiosResponse<TData>) => {
throwIfCancellationRequested(config);
transformer(response);
return response;
})
.catch((reason: unknown) => {
if (!isCancel(reason)) {
throwIfCancellationRequested(config);
if (isAxiosError(reason)) {
transformer(reason.response as AxiosResponse<TData>);
}
}
throw config.errorHandler?.(reason) ?? reason;
});
} }

View File

@ -1,16 +1,17 @@
import { AxiosAdapterRequestType } from '../adapter'; import { AxiosAdapterRequestType } from '../adapter';
import { AxiosRequestConfig } from './Axios'; import { AxiosRequestConfig } from './Axios';
const postRE = /^POST$/i;
const getRE = /^GET$/i;
export function generateType( export function generateType(
config: AxiosRequestConfig, config: AxiosRequestConfig,
): AxiosAdapterRequestType { ): AxiosAdapterRequestType {
let requestType: AxiosAdapterRequestType = 'request'; let requestType: AxiosAdapterRequestType = 'request';
const method = config.method!.toUpperCase(); if (config.upload && postRE.test(config.method!)) {
if (config.upload && method === 'POST') {
requestType = 'upload'; requestType = 'upload';
} } else if (config.download && getRE.test(config.method!)) {
if (config.download && method === 'GET') {
requestType = 'download'; requestType = 'download';
} }

View File

@ -44,7 +44,6 @@ export function request<TData = unknown>(
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
assert(isFunction(config.adapter), 'adapter 不是一个 function'); assert(isFunction(config.adapter), 'adapter 不是一个 function');
assert(isString(config.url), 'url 不是一个 string'); assert(isString(config.url), 'url 不是一个 string');
assert(isString(config.method), 'method 不是一个 string');
const adapterConfig: AxiosAdapterRequestConfig = { const adapterConfig: AxiosAdapterRequestConfig = {
...config, ...config,

View File

@ -7,20 +7,15 @@ import {
} from 'scripts/test.utils'; } from 'scripts/test.utils';
describe('src/core/request.ts', () => { describe('src/core/request.ts', () => {
test('应该抛出异常', async () => { test('应该抛出异常', () => {
await expect(request({})).rejects.toThrowErrorMatchingInlineSnapshot( expect(request({})).rejects.toThrowErrorMatchingInlineSnapshot(
'"[axios-miniprogram]: adapter 不是一个 function"', '"[axios-miniprogram]: adapter 不是一个 function"',
); );
await expect( expect(
request({ adapter: mockAdapter() }), request({ adapter: mockAdapter() }),
).rejects.toThrowErrorMatchingInlineSnapshot( ).rejects.toThrowErrorMatchingInlineSnapshot(
'"[axios-miniprogram]: url 不是一个 string"', '"[axios-miniprogram]: url 不是一个 string"',
); );
await expect(
request({ adapter: mockAdapter(), url: 'test' }),
).rejects.toThrowErrorMatchingInlineSnapshot(
'"[axios-miniprogram]: method 不是一个 string"',
);
}); });
test('应该能够取到数据', async () => { test('应该能够取到数据', async () => {