feat: 2.0 rc
parent
04da646d4a
commit
c3a97ec729
|
@ -0,0 +1,11 @@
|
|||
# 🎨 editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
|
@ -0,0 +1,5 @@
|
|||
node_modules
|
||||
dist
|
||||
.eslintrc.js
|
||||
babel.config.js
|
||||
|
13
.eslintrc.js
13
.eslintrc.js
|
@ -1,10 +1,9 @@
|
|||
const OFF = 0;
|
||||
const WARN = 1;
|
||||
const ERROR = 2;
|
||||
const [OFF, WARN, ERROR] = [0, 1, 2];
|
||||
|
||||
module.exports = {
|
||||
env: {
|
||||
es2021: true,
|
||||
node: 10,
|
||||
},
|
||||
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
|
@ -13,6 +12,10 @@ module.exports = {
|
|||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['@typescript-eslint'],
|
||||
rules: {},
|
||||
include: ['src', '__tests__'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-explicit-any': OFF,
|
||||
'@typescript-eslint/explicit-module-boundary-types': OFF,
|
||||
'@typescript-eslint/ban-types': OFF,
|
||||
'@typescript-eslint/no-non-null-assertion': OFF,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -105,9 +105,3 @@ dist
|
|||
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
coverage
|
||||
yarn-error.log
|
||||
|
||||
|
||||
dist
|
|
@ -0,0 +1 @@
|
|||
_
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
yarn commitlint --edit "$1"
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
yarn lint-staged
|
11
.prettierrc
11
.prettierrc
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "always",
|
||||
"parser": "typescript"
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
module.exports = {
|
||||
printWidth: 80,
|
||||
tabWidth: 2,
|
||||
useTabs: false,
|
||||
semi: true,
|
||||
singleQuote: true,
|
||||
trailingComma: 'all',
|
||||
bracketSpacing: true,
|
||||
arrowParens: 'always',
|
||||
parser: 'typescript',
|
||||
};
|
20
README.md
20
README.md
|
@ -17,7 +17,7 @@ $ npm i axios-miniprogram
|
|||
|
||||
## 简介
|
||||
|
||||
小程序平台专用请求库,实现了 [axios](https://github.com/axios/axios) 大部分功能,用法只存在少许差异,如果您是 [axios](https://github.com/axios/axios) 的老用户,那么不需要学习就可以直接上手使用。
|
||||
为小程序平台量身定制的轻量级请求库,请求配置以微信小程序作为标准,其他平台兼容实现。
|
||||
|
||||
- 支持 微信小程序、支付宝小程序、百度小程序、字节跳动小程序、QQ 小程序、uniapp。
|
||||
- 支持 `Typescript`,健全的类型系统,智能的 `IDE` 提示。
|
||||
|
@ -32,6 +32,18 @@ $ npm i axios-miniprogram
|
|||
|
||||
## 使用
|
||||
|
||||
### 如何引入
|
||||
|
||||
```typescript
|
||||
// esm
|
||||
import axios from 'axios-miniprogram';
|
||||
// cjs
|
||||
const axios = require('axios-miniprogram');
|
||||
// 使用
|
||||
axios('/user');
|
||||
```
|
||||
|
||||
|
||||
### `axios(config)`
|
||||
|
||||
可以通过将相关配置传递给`axios`来发送请求。
|
||||
|
@ -314,8 +326,8 @@ axios.defaults.adapter = function adapter(adapterConfig) {
|
|||
// 请求数据
|
||||
data,
|
||||
// 请求头 同 headers
|
||||
header,
|
||||
// 请求头 同 header
|
||||
headers,
|
||||
// 请求头 同 headers
|
||||
headers,
|
||||
// 响应数据格式
|
||||
dataType,
|
||||
|
@ -342,7 +354,7 @@ axios.defaults.adapter = function adapter(adapterConfig) {
|
|||
url,
|
||||
method,
|
||||
data,
|
||||
header,
|
||||
headers,
|
||||
success,
|
||||
fail,
|
||||
});
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
import adaptive from '../src/adaptive';
|
||||
|
||||
declare global {
|
||||
namespace NodeJS {
|
||||
interface Global {
|
||||
wx: any;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe('测试 src/adaptive.ts', () => {
|
||||
it('适配成功', () => {
|
||||
const request = jest.fn();
|
||||
global.wx = {
|
||||
request,
|
||||
};
|
||||
|
||||
const adapter = adaptive();
|
||||
|
||||
expect(adapter).toBe(request);
|
||||
});
|
||||
|
||||
it('适配失败', () => {
|
||||
global.wx = void 0;
|
||||
|
||||
expect(adaptive()).toBeUndefined();
|
||||
});
|
||||
});
|
|
@ -1,109 +1,3 @@
|
|||
import axios from '../src/axios';
|
||||
import CancelToken from '../src/cancel/CancelToken';
|
||||
|
||||
describe('测试 src/axios.ts', () => {
|
||||
it('default', () => {
|
||||
axios('/test').then(void 0, (error) => {
|
||||
expect(error.isAxiosError).toBe(true);
|
||||
expect(error.message).toBe('平台适配失败,您需要参阅文档使用自定义适配器手动适配当前平台');
|
||||
});
|
||||
});
|
||||
|
||||
it('axios call', async () => {
|
||||
axios.defaults.adapter = (config): any => {
|
||||
config.success({ status: 200, data: {}, headers: {} });
|
||||
|
||||
expect(config.method).toBe(config.url.toUpperCase().replace('/', ''));
|
||||
|
||||
return 'task';
|
||||
};
|
||||
|
||||
await axios({ url: '/get' });
|
||||
await axios('/get');
|
||||
await axios.request({ url: '/get' });
|
||||
await axios.options('options');
|
||||
await axios.get('get');
|
||||
await axios.head('head');
|
||||
await axios.post('post');
|
||||
await axios.put('put');
|
||||
await axios.delete('delete');
|
||||
await axios.trace('trace');
|
||||
await axios.connect('connect');
|
||||
});
|
||||
|
||||
it('axios 携带参数', async () => {
|
||||
const url = '/test';
|
||||
const params = {
|
||||
id: 1,
|
||||
};
|
||||
|
||||
axios.defaults.adapter = (config): any => {
|
||||
config.success({ status: 200, data: {}, headers: {} });
|
||||
|
||||
expect(config.method).toBe('GET');
|
||||
expect(config.url).toBe('/test?id=1');
|
||||
|
||||
return 'task';
|
||||
};
|
||||
|
||||
await axios({
|
||||
url,
|
||||
params,
|
||||
});
|
||||
await axios(url, {
|
||||
params,
|
||||
});
|
||||
await axios.get(url, params);
|
||||
});
|
||||
|
||||
it('axios 携带数据', async () => {
|
||||
const url = '/test';
|
||||
const data = {
|
||||
id: 1,
|
||||
};
|
||||
axios.defaults.adapter = (config): any => {
|
||||
config.success({ status: 200, data: '', headers: {} });
|
||||
|
||||
expect(config.method).toBe('POST');
|
||||
expect(config.url).toBe(url);
|
||||
expect(config.data).toEqual(data);
|
||||
|
||||
return 'task';
|
||||
};
|
||||
|
||||
await axios({
|
||||
method: 'post',
|
||||
url,
|
||||
data,
|
||||
});
|
||||
await axios(url, {
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
await axios.post(url, data);
|
||||
});
|
||||
|
||||
it('axios.create 工厂方法', () => {
|
||||
const instance = axios.create();
|
||||
|
||||
expect(instance.defaults).toEqual(axios.defaults);
|
||||
});
|
||||
|
||||
it('取消请求', (done) => {
|
||||
const source = CancelToken.source();
|
||||
const instance = axios.create();
|
||||
instance.interceptors.response.use(
|
||||
(res) => {
|
||||
return res;
|
||||
},
|
||||
(err) => {
|
||||
expect(axios.isCancel(err)).toBe(true);
|
||||
done();
|
||||
}
|
||||
);
|
||||
instance('/test', {
|
||||
cancelToken: source.token,
|
||||
});
|
||||
source.cancel('取消');
|
||||
});
|
||||
test('', () => {
|
||||
expect(true).toBeTruthy();
|
||||
});
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
import Cancel from '../../src/cancel/Cancel';
|
||||
|
||||
describe('测试 src/cancel/Cancel.ts', () => {
|
||||
it('默认', () => {
|
||||
const cancel = new Cancel();
|
||||
|
||||
expect(cancel.toString()).toBe('Cancel');
|
||||
});
|
||||
|
||||
it('自定义', () => {
|
||||
const cancel = new Cancel('custom');
|
||||
|
||||
expect(cancel.toString()).toBe('Cancel: custom');
|
||||
});
|
||||
});
|
|
@ -1,27 +0,0 @@
|
|||
import CancelToken from '../../src/cancel/CancelToken';
|
||||
|
||||
describe('测试 src/cancel/CancelToken.ts', () => {
|
||||
it('实例化', () => {
|
||||
const token = new CancelToken(function (cancel) {
|
||||
cancel('取消');
|
||||
});
|
||||
|
||||
// 应该抛出取消
|
||||
expect(() => token.throwIfRequested()).toThrow();
|
||||
});
|
||||
|
||||
it('工厂方法', () => {
|
||||
const source = CancelToken.source();
|
||||
|
||||
// 还没有取消 返回 Undefuned
|
||||
expect(source.token.throwIfRequested()).toBeUndefined();
|
||||
|
||||
source.cancel('取消');
|
||||
|
||||
// 应该抛出取消
|
||||
expect(() => source.token.throwIfRequested()).toThrow();
|
||||
|
||||
// 重复取消无效
|
||||
source.cancel('取消');
|
||||
});
|
||||
});
|
|
@ -1,12 +0,0 @@
|
|||
import isCancel from '../../src/cancel/isCancel';
|
||||
import Cancel from '../../src/cancel/Cancel';
|
||||
|
||||
describe('测试 src/cancel/isCancel', () => {
|
||||
it('是一个取消?', () => {
|
||||
const cancel1 = {};
|
||||
const cancel2 = new Cancel();
|
||||
|
||||
expect(isCancel(cancel1)).toBe(false);
|
||||
expect(isCancel(cancel2)).toBe(true);
|
||||
});
|
||||
});
|
|
@ -1,63 +0,0 @@
|
|||
import Axios from '../../src/core/Axios';
|
||||
|
||||
const instance = new Axios();
|
||||
|
||||
describe('测试 src/core/Axios.ts', () => {
|
||||
it('defaults', () => {
|
||||
expect(instance.defaults).toEqual({});
|
||||
});
|
||||
|
||||
it('getUri', () => {
|
||||
expect(instance.getUri({})).toEqual('');
|
||||
expect(instance.getUri({ url: '/test' })).toEqual('/test');
|
||||
expect(instance.getUri({ url: '', params: { id: 1 } })).toEqual('id=1');
|
||||
expect(instance.getUri({ url: '/test', params: { id: 1 } })).toEqual('/test?id=1');
|
||||
});
|
||||
|
||||
it('interceptors 成功', () => {
|
||||
instance.defaults.adapter = function adapter({ data, success }): any {
|
||||
expect(data).toBe('interceptors_request');
|
||||
|
||||
success({ data: 'data', headers: {} });
|
||||
|
||||
return 'task';
|
||||
};
|
||||
|
||||
instance.interceptors.request.use(function (config) {
|
||||
config.data = 'interceptors_request';
|
||||
return config;
|
||||
});
|
||||
|
||||
instance.interceptors.response.use(function (response) {
|
||||
response.data = 'interceptors_response';
|
||||
return response;
|
||||
});
|
||||
|
||||
instance
|
||||
.request({
|
||||
method: 'post',
|
||||
data: '',
|
||||
})
|
||||
.then(({ data }) => expect(data).toBe('interceptors_response'));
|
||||
});
|
||||
|
||||
it('interceptors 失败', () => {
|
||||
instance.interceptors.response.use((response) => Promise.reject(response));
|
||||
|
||||
instance
|
||||
.request({
|
||||
method: 'post',
|
||||
data: '',
|
||||
})
|
||||
.then(void 0, (error) => expect(error.data).toBe('interceptors_response'));
|
||||
|
||||
instance.interceptors.request.use((config) => Promise.reject(config));
|
||||
|
||||
instance
|
||||
.request({
|
||||
method: 'post',
|
||||
data: '',
|
||||
})
|
||||
.then(void 0, (error) => expect(error.method).toBe('post'));
|
||||
});
|
||||
});
|
|
@ -1,61 +0,0 @@
|
|||
import InterceptorManager from '../../src/core/InterceptorManager';
|
||||
|
||||
describe('测试 src/core/InterceptorManager.ts', () => {
|
||||
it('实例化', () => {
|
||||
const interceptor = new InterceptorManager();
|
||||
const executor = jest.fn();
|
||||
|
||||
interceptor.forEach(executor);
|
||||
|
||||
// executor 不应该被执行
|
||||
expect(executor.mock.calls.length).toBe(0);
|
||||
});
|
||||
|
||||
it('注册和取消注册', () => {
|
||||
const interceptor = new InterceptorManager();
|
||||
const executor1 = jest.fn();
|
||||
const executor2 = jest.fn();
|
||||
const id1 = interceptor.use(() => void 0);
|
||||
const id2 = interceptor.use(() => void 0);
|
||||
interceptor.forEach(executor1);
|
||||
|
||||
// executor1 应该被执行了两次
|
||||
expect(executor1.mock.calls.length).toBe(2);
|
||||
|
||||
interceptor.eject(id1);
|
||||
interceptor.eject(id2);
|
||||
interceptor.forEach(executor2);
|
||||
|
||||
// executor2 不应该被执行
|
||||
expect(executor2.mock.calls.length).toBe(0);
|
||||
});
|
||||
|
||||
it('倒序遍历', () => {
|
||||
const interceptor = new InterceptorManager();
|
||||
let id = 0;
|
||||
|
||||
// 应该后被执行
|
||||
interceptor.use((id) => expect(id).toBe(1));
|
||||
|
||||
// 应该先被执行
|
||||
interceptor.use((id) => expect(id).toBe(0));
|
||||
|
||||
interceptor.forEach(({ resolved }) => {
|
||||
resolved(id++);
|
||||
}, 'reverse');
|
||||
});
|
||||
|
||||
it('异常', () => {
|
||||
const interceptor = new InterceptorManager();
|
||||
|
||||
interceptor.use(
|
||||
() => void 0,
|
||||
(error: any) => {
|
||||
expect(error).toBe('error');
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
interceptor.forEach(({ rejected }) => rejected?.('error'));
|
||||
});
|
||||
});
|
|
@ -1,55 +0,0 @@
|
|||
import { CancelAction } from '../../src/types';
|
||||
import dispatchRequest from '../../src/core/dispatchRequest';
|
||||
import CancelToken from '../../src/cancel/CancelToken';
|
||||
import isCancel from '../../src/cancel/isCancel';
|
||||
|
||||
describe('测试 src/core/dispatchRequest.ts', () => {
|
||||
it('默认', () => {
|
||||
dispatchRequest({}).then(void 0, (err) => {
|
||||
expect(err.message).toBe('平台适配失败,您需要参阅文档使用自定义适配器手动适配当前平台');
|
||||
});
|
||||
});
|
||||
|
||||
it('请求失败', () => {
|
||||
dispatchRequest({
|
||||
adapter({ success }): any {
|
||||
success({ status: 200, data: '' });
|
||||
|
||||
return 'task';
|
||||
},
|
||||
validateStatus(status) {
|
||||
return status === -1;
|
||||
},
|
||||
}).then(void 0, (err) => expect(err.response.status).toBe(200));
|
||||
});
|
||||
|
||||
it('自定义错误处理', () => {
|
||||
dispatchRequest({
|
||||
adapter({ fail }): any {
|
||||
fail({});
|
||||
|
||||
return 'task';
|
||||
},
|
||||
errorHandler(error) {
|
||||
error.errorHandler = true;
|
||||
return error;
|
||||
},
|
||||
}).then(void 0, (error) => expect(error.errorHandler).toBe(true));
|
||||
});
|
||||
|
||||
it('取消请求', () => {
|
||||
let cancel: CancelAction;
|
||||
|
||||
dispatchRequest({
|
||||
adapter({ success }) {
|
||||
cancel();
|
||||
setTimeout(() => {
|
||||
success({ status: 200, data: '' });
|
||||
});
|
||||
},
|
||||
cancelToken: new CancelToken(function executor(c) {
|
||||
cancel = c;
|
||||
}),
|
||||
}).then(void 0, (err) => expect(isCancel(err)).toBe(true));
|
||||
});
|
||||
});
|
|
@ -1,35 +0,0 @@
|
|||
import flattenHeaders from '../../src/core/flattenHeaders';
|
||||
|
||||
describe('测试 src/core/flattenHeaders.ts', () => {
|
||||
it('默认', () => {
|
||||
expect(flattenHeaders({})).toEqual({});
|
||||
expect(flattenHeaders({ headers: {} })).toEqual({});
|
||||
});
|
||||
|
||||
it('默认 get', () => {
|
||||
expect(
|
||||
flattenHeaders({
|
||||
headers: {
|
||||
common: { common: 'common' },
|
||||
get: { get: 'get' },
|
||||
post: { post: 'post' },
|
||||
rest: 'rest',
|
||||
},
|
||||
})
|
||||
).toEqual({ common: 'common', get: 'get', rest: 'rest' });
|
||||
});
|
||||
|
||||
it('拉平', () => {
|
||||
expect(
|
||||
flattenHeaders({
|
||||
method: 'post',
|
||||
headers: {
|
||||
common: { common: 'common' },
|
||||
get: { get: 'get' },
|
||||
post: { post: 'post' },
|
||||
rest: 'rest',
|
||||
},
|
||||
})
|
||||
).toEqual({ common: 'common', post: 'post', rest: 'rest' });
|
||||
});
|
||||
});
|
|
@ -1,57 +0,0 @@
|
|||
import { AxiosRequestConfig } from '../../src/types';
|
||||
import mergeConfig from '../../src/core/mergeConfig';
|
||||
import defaults from '../../src/defaults';
|
||||
|
||||
describe('测试 src/core/mergeConfig.ts', () => {
|
||||
it('默认', () => {
|
||||
expect(mergeConfig()).toEqual({});
|
||||
|
||||
expect(mergeConfig({ baseURL: 'https://www.xxx.com' })).toEqual({ baseURL: 'https://www.xxx.com' });
|
||||
|
||||
expect(mergeConfig(void 0, { baseURL: 'https://www.xxx.com' })).toEqual({ baseURL: 'https://www.xxx.com' });
|
||||
});
|
||||
|
||||
it('只取 config2', () => {
|
||||
const config2 = { url: 'https://www.config2.com', data: { config2: 0 } };
|
||||
const config = mergeConfig(defaults, config2);
|
||||
|
||||
expect(config.url).toEqual(config2.url);
|
||||
expect(config.data).toEqual(config2.data);
|
||||
});
|
||||
|
||||
it('优先取 config2', () => {
|
||||
expect(mergeConfig(defaults, {})).toEqual(defaults);
|
||||
|
||||
const config2: AxiosRequestConfig = {
|
||||
baseURL: 'https://www.config2.com',
|
||||
method: 'post',
|
||||
timeout: 10000,
|
||||
};
|
||||
|
||||
const config = mergeConfig(defaults, config2);
|
||||
|
||||
expect(config.baseURL).toEqual(config2.baseURL);
|
||||
expect(config.method).toEqual(config2.method);
|
||||
expect(config.timeout).toEqual(config2.timeout);
|
||||
});
|
||||
|
||||
it('深度合并', () => {
|
||||
const config1 = { params: { config1: 0 }, headers: { Config1: '0' } };
|
||||
const config2 = { params: { config2: 0 }, headers: { Config2: '0' } };
|
||||
|
||||
expect(mergeConfig(config1, {})).toEqual(config1);
|
||||
|
||||
expect(mergeConfig(config1, config2)).toEqual({
|
||||
params: { config1: 0, config2: 0 },
|
||||
headers: { Config1: '0', Config2: '0' },
|
||||
});
|
||||
|
||||
expect(mergeConfig({ params: {} }, { params: { config: 'config2' } })).toEqual({
|
||||
params: { config: 'config2' },
|
||||
});
|
||||
|
||||
expect(mergeConfig({ params: { config: 'config1' } }, {})).toEqual({
|
||||
params: { config: 'config1' },
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,36 +0,0 @@
|
|||
import request from '../../src/core/request';
|
||||
import CancelToken from '../../src/cancel/CancelToken';
|
||||
import isCancel from '../../src/cancel/isCancel';
|
||||
|
||||
describe('测试 src/core/request.ts', () => {
|
||||
it('默认', () => {
|
||||
request({}).then(void 0, (err) =>
|
||||
expect(err.message).toBe('平台适配失败,您需要参阅文档使用自定义适配器手动适配当前平台')
|
||||
);
|
||||
});
|
||||
|
||||
it('请求失败', () => {
|
||||
request({
|
||||
adapter({ fail }): any {
|
||||
fail({});
|
||||
|
||||
return 'task';
|
||||
},
|
||||
}).then(void 0, (err) => expect(err.message).toBe('配置不正确或者网络异常'));
|
||||
});
|
||||
|
||||
it('取消请求', () => {
|
||||
request({
|
||||
adapter({ fail }) {
|
||||
setTimeout(fail);
|
||||
|
||||
return {
|
||||
abort: jest.fn(),
|
||||
};
|
||||
},
|
||||
cancelToken: new CancelToken(function executor(c) {
|
||||
c();
|
||||
}),
|
||||
}).then(void 0, (err) => expect(isCancel(err)).toBe(true));
|
||||
});
|
||||
});
|
|
@ -1,27 +0,0 @@
|
|||
import { Data } from '../../src/types';
|
||||
import transformData from '../../src/core/transformData';
|
||||
|
||||
describe('测试 src/core/transformData.ts', () => {
|
||||
it('默认', () => {
|
||||
expect(transformData({ a: 1 }, {})).toEqual({ a: 1 });
|
||||
});
|
||||
|
||||
it('转换', () => {
|
||||
function transform(data: Data) {
|
||||
return data + '1';
|
||||
}
|
||||
expect(transformData('1', {}, transform)).toEqual('11');
|
||||
});
|
||||
|
||||
it('多次转换', () => {
|
||||
const transforms = [
|
||||
function transform(data: Data) {
|
||||
return data + '1';
|
||||
},
|
||||
function transform(data: Data) {
|
||||
return data + '1';
|
||||
},
|
||||
];
|
||||
expect(transformData('1', {}, transforms)).toEqual('111');
|
||||
});
|
||||
});
|
|
@ -1,13 +0,0 @@
|
|||
import { methodToLowercase, methodToUppercase } from '../../src/core/transformMethod';
|
||||
|
||||
describe('测试 src/core/transformMethod.ts', () => {
|
||||
it('默认', () => {
|
||||
expect(methodToLowercase()).toBe('get');
|
||||
expect(methodToUppercase()).toBe('GET');
|
||||
});
|
||||
|
||||
it('传参', () => {
|
||||
expect(methodToLowercase('POST')).toBe('post');
|
||||
expect(methodToUppercase('post')).toBe('POST');
|
||||
});
|
||||
});
|
|
@ -1,42 +0,0 @@
|
|||
import transformRequest from '../../src/core/transformRequest';
|
||||
|
||||
describe('测试 src/core/transformRequest.ts', () => {
|
||||
it('默认', () => {
|
||||
expect(transformRequest({})).toEqual({
|
||||
url: '/',
|
||||
method: 'GET',
|
||||
headers: void 0,
|
||||
data: void 0,
|
||||
dataType: void 0,
|
||||
enableCache: void 0,
|
||||
enableHttp2: void 0,
|
||||
enableQuic: void 0,
|
||||
header: void 0,
|
||||
responseType: void 0,
|
||||
sslVerify: void 0,
|
||||
timeout: void 0,
|
||||
});
|
||||
});
|
||||
|
||||
it('基本', () => {
|
||||
const request = transformRequest({
|
||||
baseURL: 'https://www.xxx.com///',
|
||||
method: 'get',
|
||||
url: '/test',
|
||||
params: {
|
||||
id: 1,
|
||||
},
|
||||
});
|
||||
const request2 = transformRequest({
|
||||
baseURL: 'https://www.xxx.com',
|
||||
method: 'get',
|
||||
url: 'https://www.yyy.com/test',
|
||||
params: {
|
||||
id: 1,
|
||||
},
|
||||
});
|
||||
|
||||
expect(request.url).toEqual('https://www.xxx.com/test?id=1');
|
||||
expect(request2.url).toEqual('https://www.yyy.com/test?id=1');
|
||||
});
|
||||
});
|
|
@ -1,38 +0,0 @@
|
|||
import transformResponse from '../../src/core/transformResponse';
|
||||
|
||||
describe('测试 src/core/transformResponse.ts', () => {
|
||||
it('默认', () => {
|
||||
expect(transformResponse({ data: {} }, {})).toEqual({
|
||||
status: 400,
|
||||
statusText: 'Bad Adapter',
|
||||
data: {},
|
||||
headers: {},
|
||||
config: {},
|
||||
cookies: void 0,
|
||||
profile: void 0,
|
||||
});
|
||||
});
|
||||
|
||||
it('status + headers', () => {
|
||||
expect(transformResponse({ status: 200, headers: { status: 'ok' }, data: {} }, {})).toEqual({
|
||||
status: 200,
|
||||
statusText: 'OK',
|
||||
data: {},
|
||||
headers: { status: 'ok' },
|
||||
config: {},
|
||||
cookies: void 0,
|
||||
profile: void 0,
|
||||
});
|
||||
});
|
||||
it('statusCode + header', () => {
|
||||
expect(transformResponse({ statusCode: 204, header: { status: 'ok' }, data: {} }, {})).toEqual({
|
||||
status: 204,
|
||||
statusText: '',
|
||||
data: {},
|
||||
headers: { status: 'ok' },
|
||||
config: {},
|
||||
cookies: void 0,
|
||||
profile: void 0,
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,82 +0,0 @@
|
|||
import buildURL from '../../src/helpers/buildURL';
|
||||
|
||||
describe('测试 src/helpers/buildURL.ts', () => {
|
||||
it('url', () => {
|
||||
expect(buildURL('/test')).toBe('/test');
|
||||
expect(buildURL('/test?id=1')).toBe('/test?id=1');
|
||||
});
|
||||
|
||||
it('url + params', () => {
|
||||
expect(
|
||||
buildURL('/test', {
|
||||
test: 1,
|
||||
})
|
||||
).toBe('/test?test=1');
|
||||
expect(
|
||||
buildURL('/test?id=1', {
|
||||
test: 1,
|
||||
})
|
||||
).toBe('/test?id=1&test=1');
|
||||
});
|
||||
|
||||
it('url + params + paramsSerializer', () => {
|
||||
expect(
|
||||
buildURL(
|
||||
'/test',
|
||||
{
|
||||
test: 1,
|
||||
},
|
||||
() => 'paramsSerializer=ok'
|
||||
)
|
||||
).toBe('/test?paramsSerializer=ok');
|
||||
expect(
|
||||
buildURL(
|
||||
'/test?id=1',
|
||||
{
|
||||
test: 1,
|
||||
},
|
||||
() => 'paramsSerializer=ok'
|
||||
)
|
||||
).toBe('/test?id=1¶msSerializer=ok');
|
||||
});
|
||||
|
||||
it('params 是数组', () => {
|
||||
expect(
|
||||
buildURL('/test', {
|
||||
ids: [1],
|
||||
})
|
||||
).toBe('/test?ids[]=1');
|
||||
});
|
||||
|
||||
it('params 是时间对象', () => {
|
||||
const date = new Date();
|
||||
expect(
|
||||
buildURL('/test', {
|
||||
date,
|
||||
})
|
||||
).toBe(`/test?date=${date.toISOString()}`);
|
||||
});
|
||||
|
||||
it('params 是普通对象', () => {
|
||||
const obj = {};
|
||||
expect(
|
||||
buildURL('/test', {
|
||||
obj,
|
||||
})
|
||||
).toBe(`/test?obj=%7B%7D`);
|
||||
});
|
||||
|
||||
it('删除哈希', () => {
|
||||
expect(buildURL('/test#192929')).toBe('/test');
|
||||
});
|
||||
|
||||
it('容错', () => {
|
||||
expect(
|
||||
buildURL('/test', {
|
||||
null: null,
|
||||
undefined: void 0,
|
||||
NaN: NaN,
|
||||
})
|
||||
).toBe('/test');
|
||||
});
|
||||
});
|
|
@ -1,8 +0,0 @@
|
|||
import combineURL from '../../src/helpers/combineURL';
|
||||
|
||||
describe('测试 src/helpers/combineURL.ts', () => {
|
||||
it('run', () => {
|
||||
expect(combineURL('1/2', '3/4')).toBe('1/2/3/4');
|
||||
expect(combineURL('1/2////', '////3/4')).toBe('1/2/3/4');
|
||||
});
|
||||
});
|
|
@ -1,21 +0,0 @@
|
|||
import dynamicURL from '../../src/helpers/dynamicURL';
|
||||
|
||||
describe('测试 src/helpers/dynamicURL.ts', () => {
|
||||
it('run', () => {
|
||||
expect(dynamicURL('http://www.api.com/user/:id', { id: 1 })).toBe(
|
||||
'http://www.api.com/user/1',
|
||||
);
|
||||
expect(dynamicURL('http://www.api.com:8080/user/:id', { id: 1 })).toBe(
|
||||
'http://www.api.com:8080/user/1',
|
||||
);
|
||||
expect(dynamicURL('http://www.api.com/user/:id', { id: 1 })).toBe(
|
||||
'http://www.api.com/user/1',
|
||||
);
|
||||
expect(dynamicURL('http://www.api.com/user:id/', { id: 1 })).toBe(
|
||||
'http://www.api.com/user1/',
|
||||
);
|
||||
expect(dynamicURL('http://www.api.com/:id/user', { id: 1 })).toBe(
|
||||
'http://www.api.com/1/user',
|
||||
);
|
||||
});
|
||||
});
|
|
@ -1,10 +0,0 @@
|
|||
import isAbsoluteURL from '../../src/helpers/isAbsoluteURL';
|
||||
|
||||
describe('测试 src/helpers/isAbsoluteURL.ts', () => {
|
||||
it('run', () => {
|
||||
expect(isAbsoluteURL('1/2')).toBe(false);
|
||||
expect(isAbsoluteURL('/1/2')).toBe(false);
|
||||
expect(isAbsoluteURL('///1/2')).toBe(true);
|
||||
expect(isAbsoluteURL('http://1/2')).toBe(true);
|
||||
});
|
||||
});
|
|
@ -1,41 +0,0 @@
|
|||
import { encode, isDate, isPlainObject, deepMerge, pick, omit } from '../../src/helpers/utils';
|
||||
|
||||
describe('测试 src/helpers/utils.ts', () => {
|
||||
it('encode 特殊字符转换', () => {
|
||||
expect(encode('@:, []$')).toBe('@:,+[]$');
|
||||
});
|
||||
|
||||
it('isDate', () => {
|
||||
expect(isDate(new Date())).toBe(true);
|
||||
expect(isDate('')).toBe(false);
|
||||
expect(isDate(Date)).toBe(false);
|
||||
});
|
||||
|
||||
it('isPlainObject', () => {
|
||||
expect(isPlainObject({})).toBe(true);
|
||||
expect(isPlainObject(Object.create(null))).toBe(true);
|
||||
expect(isPlainObject('')).toBe(false);
|
||||
expect(isPlainObject(Object)).toBe(false);
|
||||
});
|
||||
|
||||
it('deepMerge', () => {
|
||||
expect(deepMerge({}, {})).toEqual({});
|
||||
expect(deepMerge({ a: 0, b: '1', c: { a: 0, b: '1' } }, { a: 1, b: '1', c: { a: 1, b: '1' } })).toEqual({
|
||||
a: 1,
|
||||
b: '1',
|
||||
c: { a: 1, b: '1' },
|
||||
});
|
||||
});
|
||||
|
||||
it('pick', () => {
|
||||
expect(pick({})).toEqual({});
|
||||
|
||||
expect(pick({ a: 0, b: 0 }, 'a')).toEqual({ a: 0 });
|
||||
});
|
||||
|
||||
it('omit', () => {
|
||||
expect(omit({})).toEqual({});
|
||||
|
||||
expect(omit({ a: 0, b: 0 }, 'a')).toEqual({ b: 0 });
|
||||
});
|
||||
});
|
|
@ -1,26 +1,4 @@
|
|||
const runtimeVersion = require('./package.json').dependencies[
|
||||
'@babel/runtime'
|
||||
].replace(/^[^0-9]*/, '');
|
||||
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
targets: {
|
||||
ie: '8',
|
||||
},
|
||||
},
|
||||
],
|
||||
'@babel/preset-typescript',
|
||||
],
|
||||
plugins: [
|
||||
[
|
||||
'@babel/transform-runtime',
|
||||
{
|
||||
version: runtimeVersion,
|
||||
},
|
||||
],
|
||||
],
|
||||
presets: ['@babel/preset-typescript'],
|
||||
exclude: 'node_modules/**',
|
||||
};
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* feat:新增功能
|
||||
* fix:bug 修复
|
||||
* docs:文档更新
|
||||
* style:不影响程序逻辑的代码修改(修改空白字符,格式缩进,补全缺失的分号等,没有改变代码逻辑)
|
||||
* refactor:重构代码(既没有新增功能,也没有修复 bug)
|
||||
* perf:性能, 体验优化
|
||||
* test:新增测试用例或是更新现有测试
|
||||
* build:主要目的是修改项目构建系统(例如 glup,webpack,rollup 的配置等)的提交
|
||||
* ci:主要目的是修改项目继续集成流程(例如 Travis,Jenkins,GitLab CI,Circle等)的提交
|
||||
* chore:不属于以上类型的其他类型,比如构建流程, 依赖管理
|
||||
* revert:回滚某个更早之前的提交
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
extends: ['@commitlint/config-conventional'],
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
declare const uni: any;
|
||||
declare const wx: any;
|
||||
declare const my: any;
|
||||
declare const swan: any;
|
||||
declare const tt: any;
|
||||
declare const qq: any;
|
||||
declare const qh: any;
|
||||
declare const ks: any;
|
||||
declare const dd: any;
|
||||
|
||||
declare interface AnyObject<T = any> {
|
||||
[key: string]: T;
|
||||
[key: number]: T;
|
||||
}
|
36
package.json
36
package.json
|
@ -1,17 +1,16 @@
|
|||
{
|
||||
"name": "axios-miniprogram",
|
||||
"version": "1.3.0",
|
||||
"version": "1.3.1",
|
||||
"description": "基于 Promise 的 HTTP 请求库,适用于各大小程序平台。",
|
||||
"main": "dist/cjs/axios-miniprogram.js",
|
||||
"module": "dist/esm/axios-miniprogram.js",
|
||||
"types": "types/index.d.ts",
|
||||
"types": "dist/@types/axios-miniprogram/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"types"
|
||||
"dist"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/zjx0905/axios-miniprogram.git"
|
||||
"url": "git+https://github.com/fluffff/axios-miniprogram.git"
|
||||
},
|
||||
"keywords": [
|
||||
"axios",
|
||||
|
@ -25,32 +24,45 @@
|
|||
},
|
||||
"homepage": "https://github.com/fluffff/axios-miniprogram#readme",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "rollup --config",
|
||||
"test": "jest"
|
||||
"test": "jest",
|
||||
"lint": "eslint",
|
||||
"format": "prettier --check --write '{src,__tests__}/**/*.{js,ts,tsx}'",
|
||||
"version": "yarn test && yarn build",
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.14.0",
|
||||
"@babel/plugin-transform-runtime": "^7.13.15",
|
||||
"@babel/preset-env": "^7.14.1",
|
||||
"@babel/preset-typescript": "^7.13.0",
|
||||
"@commitlint/cli": "^12.1.4",
|
||||
"@commitlint/config-conventional": "^12.1.4",
|
||||
"@rollup/plugin-babel": "^5.3.0",
|
||||
"@rollup/plugin-commonjs": "^19.0.0",
|
||||
"@rollup/plugin-node-resolve": "^13.0.0",
|
||||
"@rollup/plugin-typescript": "^8.2.1",
|
||||
"@types/jest": "^26.0.23",
|
||||
"@typescript-eslint/eslint-plugin": "^4.22.1",
|
||||
"@typescript-eslint/parser": "^4.22.1",
|
||||
"eslint": "^7.26.0",
|
||||
"husky": "^6.0.0",
|
||||
"jest": "^26.6.3",
|
||||
"lint-staged": "10.0.0",
|
||||
"prettier": "2.2.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup": "^2.47.0",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"rollup-plugin-typescript2": "^0.30.0",
|
||||
"ts-node": "^9.1.1",
|
||||
"tslib": "^2.2.0",
|
||||
"typescript": "^4.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.14.0"
|
||||
"lint-staged": {
|
||||
"*.ts": [
|
||||
"yarn lint",
|
||||
"yarn format",
|
||||
"yarn test"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,44 +1,42 @@
|
|||
const path = require('path');
|
||||
const rimraf = require('rimraf');
|
||||
const { nodeResolve } = require('@rollup/plugin-node-resolve');
|
||||
const { babel } = require('@rollup/plugin-babel');
|
||||
const typescript = require('@rollup/plugin-typescript');
|
||||
const commonjs = require('@rollup/plugin-commonjs');
|
||||
const { terser } = require('rollup-plugin-terser');
|
||||
const { DEFAULT_EXTENSIONS } = require('@babel/core');
|
||||
import path from 'path';
|
||||
import rimraf from 'rimraf';
|
||||
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
||||
import { babel } from '@rollup/plugin-babel';
|
||||
import typescript from 'rollup-plugin-typescript2';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
import { DEFAULT_EXTENSIONS } from '@babel/core';
|
||||
|
||||
const pkg = require('./package.json');
|
||||
import filterEmptyLines from './scripts/@rollup/plugin-filter-empty-lines';
|
||||
import pkg from './package.json';
|
||||
|
||||
const entryFilePath = path.resolve(__dirname, 'src/index.ts');
|
||||
const buildPath = path.resolve(__dirname, 'dist');
|
||||
const distPath = path.resolve(__dirname, 'dist');
|
||||
const pkgName = pkg.name;
|
||||
|
||||
function resolveOutputFilePath(format) {
|
||||
return path.resolve(buildPath, format, pkgName + '.js');
|
||||
}
|
||||
|
||||
const extensions = [].concat(DEFAULT_EXTENSIONS, '.ts');
|
||||
|
||||
const basePlugins = [
|
||||
const plugins = [
|
||||
nodeResolve({
|
||||
extensions,
|
||||
}),
|
||||
typescript({}),
|
||||
typescript({
|
||||
useTsconfigDeclarationDir: true,
|
||||
}),
|
||||
babel({
|
||||
extensions,
|
||||
babelHelpers: 'runtime',
|
||||
babelHelpers: 'bundled',
|
||||
comments: false,
|
||||
}),
|
||||
commonjs(),
|
||||
commonjs({
|
||||
include: /node_modules/,
|
||||
}),
|
||||
filterEmptyLines(),
|
||||
];
|
||||
|
||||
function createConfig(format) {
|
||||
const isUmd = format === 'umd';
|
||||
const plugins = [].concat(basePlugins);
|
||||
|
||||
if (isUmd) {
|
||||
plugins.push(terser());
|
||||
}
|
||||
function resolveOutputFilePath(format) {
|
||||
return path.resolve(distPath, format, `${pkgName}.js`);
|
||||
}
|
||||
|
||||
function generateConfig(format) {
|
||||
return {
|
||||
input: entryFilePath,
|
||||
output: {
|
||||
|
@ -46,30 +44,26 @@ function createConfig(format) {
|
|||
format,
|
||||
name: pkgName,
|
||||
exports: 'default',
|
||||
},
|
||||
external(id) {
|
||||
if (isUmd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return /@babel\/runtime/.test(id);
|
||||
indent: false,
|
||||
},
|
||||
plugins,
|
||||
};
|
||||
}
|
||||
|
||||
let run;
|
||||
const promise = new Promise(function (resolve, reject) {
|
||||
run = function (error) {
|
||||
if (error) {
|
||||
reject(error);
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
run = (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve([createConfig('esm'), createConfig('cjs'), createConfig('umd')]);
|
||||
resolve([generateConfig('esm'), generateConfig('cjs')]);
|
||||
};
|
||||
});
|
||||
|
||||
module.exports = function () {
|
||||
rimraf(buildPath, run);
|
||||
export default () => {
|
||||
rimraf(distPath, run);
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
module.exports = function filterEmptyLines() {
|
||||
const filterREG = /\s{2,}|\n/g;
|
||||
|
||||
return {
|
||||
transform(code) {
|
||||
return {
|
||||
code: code.replace(filterREG, ''),
|
||||
map: null,
|
||||
};
|
||||
},
|
||||
};
|
||||
};
|
|
@ -1,39 +0,0 @@
|
|||
import { Adapter, Platform } from './types';
|
||||
import { isUndefined } from './helpers/utils';
|
||||
|
||||
// uniapp
|
||||
declare let uni: Platform;
|
||||
// 微信小程序
|
||||
declare let wx: Platform;
|
||||
// 支付宝小程序
|
||||
declare let my: Platform;
|
||||
// 百度小程序
|
||||
declare let swan: Platform;
|
||||
// 字节跳动小程序
|
||||
declare let tt: Platform;
|
||||
// QQ 小程序
|
||||
declare let qq: Platform;
|
||||
|
||||
/**
|
||||
* 自适应当前平台
|
||||
*/
|
||||
export default function adaptive(): Adapter | undefined {
|
||||
const stack: (() => Adapter)[] = [
|
||||
() => uni.request,
|
||||
() => wx.request,
|
||||
() => my.request,
|
||||
() => swan.request,
|
||||
() => tt.request,
|
||||
() => qq.request,
|
||||
];
|
||||
|
||||
let adapter: Adapter | undefined;
|
||||
|
||||
while (stack.length !== 0 && isUndefined(adapter)) {
|
||||
try {
|
||||
adapter = (stack.shift() as () => Adapter)();
|
||||
} catch (err) {}
|
||||
}
|
||||
|
||||
return adapter;
|
||||
}
|
73
src/axios.ts
73
src/axios.ts
|
@ -1,62 +1,59 @@
|
|||
import { AxiosRequestConfig, Data, AxiosResponse, AxiosBaseInstance, AxiosInstance } from './types';
|
||||
import Axios from './core/Axios';
|
||||
import mergeConfig from './core/mergeConfig';
|
||||
import CancelToken from './cancel/CancelToken';
|
||||
import isCancel from './cancel/isCancel';
|
||||
import { AxiosAdapter, createAdapter, AxiosPlatform } from './core/adapter';
|
||||
import Axios, {
|
||||
AxiosConstructor,
|
||||
AxiosRequestConfig,
|
||||
AxiosResponse,
|
||||
} from './core/Axios';
|
||||
import { CancelToken, CancelTokenConstructor, isCancel } from './core/cancel';
|
||||
import { mergeConfig } from './core/mergeConfig';
|
||||
import { isString } from './utils';
|
||||
import defaults from './defaults';
|
||||
|
||||
/**
|
||||
* 创建一个新的 Axios 实例
|
||||
*
|
||||
* 返回一个 Axios 实例增强
|
||||
*/
|
||||
export interface AxiosInstance extends Axios {
|
||||
<TData = any>(config: AxiosRequestConfig): Promise<AxiosResponse<TData>>;
|
||||
<TData = any>(url: string, config?: AxiosRequestConfig): Promise<
|
||||
AxiosResponse<TData>
|
||||
>;
|
||||
}
|
||||
|
||||
export interface AxiosStatic extends AxiosInstance {
|
||||
Axios: AxiosConstructor;
|
||||
CancelToken: CancelTokenConstructor;
|
||||
create(defaults?: AxiosRequestConfig): AxiosInstance;
|
||||
createAdapter(platform: AxiosPlatform): AxiosAdapter | undefined;
|
||||
isCancel(value: any): boolean;
|
||||
}
|
||||
|
||||
function createInstance(defaults: AxiosRequestConfig): AxiosInstance {
|
||||
const instance = new Axios(defaults);
|
||||
|
||||
/**
|
||||
* 支持重载的 axios 函数
|
||||
*/
|
||||
function axios<T extends Data>(
|
||||
function axios<TData = any>(
|
||||
url: AxiosRequestConfig | string,
|
||||
config: AxiosRequestConfig = {}
|
||||
): Promise<AxiosResponse<T>> {
|
||||
// 调用方式一处理请求配置
|
||||
if (typeof url !== 'string') {
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<TData>> {
|
||||
if (isString(url)) {
|
||||
config = Object.assign({}, config, { url });
|
||||
} else {
|
||||
config = url;
|
||||
}
|
||||
// 调用方式二处理请求配置
|
||||
else {
|
||||
config = { ...config, url };
|
||||
}
|
||||
|
||||
return instance.request(config);
|
||||
}
|
||||
|
||||
// instance 的属性合并到 axios 函数中
|
||||
Object.assign(axios, instance);
|
||||
// instance 的方法合并到 axios 函数中
|
||||
Object.setPrototypeOf(axios, Object.getPrototypeOf(instance));
|
||||
|
||||
return axios as AxiosInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Axios 实例拓展
|
||||
*/
|
||||
const axios = createInstance(defaults);
|
||||
const axios = createInstance(defaults) as AxiosStatic;
|
||||
|
||||
// 添加 create 工厂方法
|
||||
axios.create = function create(defaults: AxiosRequestConfig = {}): AxiosBaseInstance {
|
||||
axios.Axios = Axios;
|
||||
axios.CancelToken = CancelToken;
|
||||
axios.create = function create(defaults: AxiosRequestConfig): AxiosInstance {
|
||||
return createInstance(mergeConfig(axios.defaults, defaults));
|
||||
};
|
||||
|
||||
// 添加 Axios 类
|
||||
axios.Axios = Axios;
|
||||
|
||||
// 添加 CancelToken 类
|
||||
axios.CancelToken = CancelToken;
|
||||
|
||||
// 添加 检查错误是否来自取消请求 方法
|
||||
axios.createAdapter = createAdapter;
|
||||
axios.isCancel = isCancel;
|
||||
|
||||
export default axios;
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
import { Cancel } from '../types';
|
||||
|
||||
export default class CancelClass implements Cancel {
|
||||
/**
|
||||
* @param message 取消信息
|
||||
*/
|
||||
public constructor(public message?: string) {}
|
||||
|
||||
public toString(): string {
|
||||
const message = this.message ? `: ${this.message}` : '';
|
||||
|
||||
return `Cancel${message}`;
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
import { CancelToken, CancelAction, CancelExecutor, CancelTokenSource } from '../types';
|
||||
import Cancel from './Cancel';
|
||||
|
||||
export default class CancelTokenClass implements CancelToken {
|
||||
/**
|
||||
* 取消请求
|
||||
*/
|
||||
private _reason?: Cancel;
|
||||
|
||||
public listener: Promise<Cancel>;
|
||||
|
||||
public constructor(executor: CancelExecutor) {
|
||||
let action!: CancelAction;
|
||||
|
||||
this.listener = new Promise<Cancel>((resolve) => {
|
||||
action = (message) => {
|
||||
// 防止重复取消
|
||||
if (this._reason) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._reason = new Cancel(message);
|
||||
|
||||
resolve(this._reason);
|
||||
};
|
||||
});
|
||||
|
||||
executor(action);
|
||||
}
|
||||
|
||||
public throwIfRequested(): void {
|
||||
if (this._reason) {
|
||||
throw this._reason;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回一个 CancelTokenSource
|
||||
*
|
||||
* CancelTokenSource.token 是一个 CancelToken 对象
|
||||
*
|
||||
* CancelTokenSource.cancel 是一个 CancelAction 函数
|
||||
*
|
||||
* 调用 CancelTokenSource.cancel('这里可以填写您的错误信息')
|
||||
*
|
||||
* 取消请求 CancelTokenSource.token
|
||||
*/
|
||||
public static source(): CancelTokenSource {
|
||||
let cancel!: CancelAction;
|
||||
|
||||
const token = new CancelTokenClass(function executor(action) {
|
||||
cancel = action;
|
||||
});
|
||||
|
||||
return {
|
||||
token,
|
||||
cancel,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
import Cancel from './Cancel';
|
||||
|
||||
/**
|
||||
* 是否是取消请求实例
|
||||
*
|
||||
* @param value 判断的值
|
||||
*/
|
||||
export default function isCancel(value: unknown): value is Cancel {
|
||||
return value instanceof Cancel;
|
||||
}
|
|
@ -1,131 +1,221 @@
|
|||
import {
|
||||
Method,
|
||||
Params,
|
||||
Data,
|
||||
Interceptors,
|
||||
AxiosRequestConfig,
|
||||
AxiosResponse,
|
||||
Axios,
|
||||
} from '../types';
|
||||
import buildURL from '../helpers/buildURL';
|
||||
import mergeConfig from './mergeConfig';
|
||||
import InterceptorManager from './InterceptorManager';
|
||||
import { buildURL } from '../utils';
|
||||
import { mergeConfig } from './mergeConfig';
|
||||
import { AdapterRequestMethod, AxiosAdapter } from './adapter';
|
||||
import { CancelToken } from './cancel';
|
||||
import dispatchRequest from './dispatchRequest';
|
||||
import InterceptorManager from './InterceptorManager';
|
||||
import { AxiosTransformer } from './transformData';
|
||||
|
||||
export default class AxiosClass implements Axios {
|
||||
public interceptors: Interceptors = {
|
||||
export type AxiosRequestMethodAlias =
|
||||
| 'options'
|
||||
| 'get'
|
||||
| 'head'
|
||||
| 'post'
|
||||
| 'put'
|
||||
| 'delete'
|
||||
| 'trace'
|
||||
| 'connect';
|
||||
|
||||
export type AxiosRequestMethod = AdapterRequestMethod | AxiosRequestMethodAlias;
|
||||
|
||||
export type AxiosRequestHeaders = AnyObject;
|
||||
|
||||
export type AxiosRequestParams = AnyObject;
|
||||
|
||||
export type AxiosRequestData = AnyObject;
|
||||
|
||||
export type AxiosResponseHeaders = AnyObject;
|
||||
|
||||
export interface AxiosRequestFormData extends AxiosRequestData {
|
||||
fileName: string;
|
||||
filePath: string;
|
||||
fileType?: 'image' | 'video' | 'audio';
|
||||
hideLoading?: boolean;
|
||||
}
|
||||
|
||||
export interface AxiosProgressEvent {
|
||||
progress: number;
|
||||
totalBytesSent: number;
|
||||
totalBytesExpectedToSend: number;
|
||||
}
|
||||
|
||||
export interface AxiosProgressCallback {
|
||||
(event: AxiosProgressEvent): void;
|
||||
}
|
||||
|
||||
export interface AxiosRequestConfig {
|
||||
adapter?: AxiosAdapter;
|
||||
baseURL?: string;
|
||||
cancelToken?: CancelToken;
|
||||
data?: AxiosRequestData | AxiosRequestFormData;
|
||||
dataType?: 'json' | '其他';
|
||||
enableHttp2?: boolean;
|
||||
enableQuic?: boolean;
|
||||
enableCache?: boolean;
|
||||
errorHandler?: (error: any) => Promise<any>;
|
||||
headers?: AxiosRequestHeaders;
|
||||
method?: AxiosRequestMethod;
|
||||
onUploadProgress?: AxiosProgressCallback;
|
||||
onDownloadProgress?: AxiosProgressCallback;
|
||||
params?: AxiosRequestParams;
|
||||
paramsSerializer?: (params?: AxiosRequestParams) => string;
|
||||
responseType?: 'text' | 'arraybuffer' | 'file';
|
||||
sslVerify?: boolean;
|
||||
transformRequest?: AxiosTransformer | AxiosTransformer[];
|
||||
transformResponse?: AxiosTransformer | AxiosTransformer[];
|
||||
timeout?: number;
|
||||
url?: string;
|
||||
validateStatus?: (status: number) => boolean;
|
||||
}
|
||||
|
||||
export interface AxiosResponse<TData = any> {
|
||||
status: number;
|
||||
statusText: string;
|
||||
headers: AxiosResponseHeaders;
|
||||
data: TData;
|
||||
cookies?: string[];
|
||||
profile?: AnyObject;
|
||||
}
|
||||
|
||||
export interface AxiosResponseError extends AnyObject {
|
||||
status: number;
|
||||
statusText: string;
|
||||
headers: AxiosResponseHeaders;
|
||||
}
|
||||
|
||||
export interface AxiosConstructor {
|
||||
new (config: AxiosRequestConfig): Axios;
|
||||
}
|
||||
|
||||
export default class Axios {
|
||||
public defaults: AxiosRequestConfig;
|
||||
|
||||
public interceptors = {
|
||||
request: new InterceptorManager<AxiosRequestConfig>(),
|
||||
response: new InterceptorManager<AxiosResponse>(),
|
||||
};
|
||||
|
||||
/**
|
||||
* @param defaults 自定义默认配置
|
||||
*/
|
||||
public constructor(public defaults: AxiosRequestConfig = {}) {}
|
||||
public constructor(defaults: AxiosRequestConfig = {}) {
|
||||
this.defaults = defaults;
|
||||
}
|
||||
|
||||
public getUri(config: AxiosRequestConfig): string {
|
||||
const { url = '', params, paramsSerializer } = mergeConfig(this.defaults, config);
|
||||
const { url, params, paramsSerializer } = mergeConfig(
|
||||
this.defaults,
|
||||
config,
|
||||
);
|
||||
|
||||
return buildURL(url, params, paramsSerializer).replace(/^\?/, '');
|
||||
}
|
||||
|
||||
public request<T extends Data>(config: AxiosRequestConfig): Promise<AxiosResponse<T>> {
|
||||
public request<TData = any>(
|
||||
config: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<TData>> {
|
||||
const requestConfig = mergeConfig(this.defaults, config);
|
||||
|
||||
let promiseRequest = Promise.resolve(requestConfig);
|
||||
|
||||
// 执行请求拦截器
|
||||
this.interceptors.request.forEach(function executor({ resolved, rejected }) {
|
||||
this.interceptors.request.forEach(({ resolved, rejected }) => {
|
||||
promiseRequest = promiseRequest.then(resolved, rejected);
|
||||
}, 'reverse');
|
||||
|
||||
// 发送请求
|
||||
let promiseResponse = promiseRequest.then(dispatchRequest);
|
||||
|
||||
// 执行响应拦截器
|
||||
this.interceptors.response.forEach(function executor({ resolved, rejected }) {
|
||||
this.interceptors.response.forEach(({ resolved, rejected }) => {
|
||||
promiseResponse = promiseResponse.then(resolved, rejected);
|
||||
});
|
||||
|
||||
return promiseResponse as Promise<AxiosResponse<T>>;
|
||||
return promiseResponse as Promise<AxiosResponse<TData>>;
|
||||
}
|
||||
|
||||
public options<T extends Data>(
|
||||
public options<TData = any>(
|
||||
url: string,
|
||||
config?: AxiosRequestConfig
|
||||
): Promise<AxiosResponse<T>> {
|
||||
return this._requestMethodWithoutParams<T>('options', url, void 0, config);
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<TData>> {
|
||||
return this._requestMethodWithoutParams<TData>(
|
||||
'options',
|
||||
url,
|
||||
undefined,
|
||||
config,
|
||||
);
|
||||
}
|
||||
|
||||
public get<T extends Data>(
|
||||
public get<TData = any>(
|
||||
url: string,
|
||||
params?: Params,
|
||||
config?: AxiosRequestConfig
|
||||
): Promise<AxiosResponse<T>> {
|
||||
return this._requestMethodWithoutParams<T>('get', url, params, config);
|
||||
params?: AnyObject,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<TData>> {
|
||||
return this._requestMethodWithoutParams<TData>('get', url, params, config);
|
||||
}
|
||||
|
||||
public head<T extends Data>(
|
||||
public head<TData = any>(
|
||||
url: string,
|
||||
params?: Params,
|
||||
config?: AxiosRequestConfig
|
||||
): Promise<AxiosResponse<T>> {
|
||||
return this._requestMethodWithoutParams<T>('head', url, params, config);
|
||||
params?: AnyObject,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<TData>> {
|
||||
return this._requestMethodWithoutParams<TData>('head', url, params, config);
|
||||
}
|
||||
|
||||
public post<T extends Data>(
|
||||
public post<TData = any>(
|
||||
url: string,
|
||||
data?: Data,
|
||||
config?: AxiosRequestConfig
|
||||
): Promise<AxiosResponse<T>> {
|
||||
return this._requestMethodWithoutData<T>('post', url, data, config);
|
||||
data?: AnyObject,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<TData>> {
|
||||
return this._requestMethodWithoutData<TData>('post', url, data, config);
|
||||
}
|
||||
|
||||
public put<T extends Data>(
|
||||
public put<TData = any>(
|
||||
url: string,
|
||||
data?: Data,
|
||||
config?: AxiosRequestConfig
|
||||
): Promise<AxiosResponse<T>> {
|
||||
return this._requestMethodWithoutData<T>('put', url, data, config);
|
||||
data?: AnyObject,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<TData>> {
|
||||
return this._requestMethodWithoutData<TData>('put', url, data, config);
|
||||
}
|
||||
|
||||
public delete<T extends Data>(
|
||||
public delete<TData = any>(
|
||||
url: string,
|
||||
params?: Params,
|
||||
config?: AxiosRequestConfig
|
||||
): Promise<AxiosResponse<T>> {
|
||||
return this._requestMethodWithoutParams<T>('delete', url, params, config);
|
||||
params?: AnyObject,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<TData>> {
|
||||
return this._requestMethodWithoutParams<TData>(
|
||||
'delete',
|
||||
url,
|
||||
params,
|
||||
config,
|
||||
);
|
||||
}
|
||||
|
||||
public trace<T extends Data>(
|
||||
public trace<TData = any>(
|
||||
url: string,
|
||||
config?: AxiosRequestConfig
|
||||
): Promise<AxiosResponse<T>> {
|
||||
return this._requestMethodWithoutParams<T>('trace', url, void 0, config);
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<TData>> {
|
||||
return this._requestMethodWithoutParams<TData>(
|
||||
'trace',
|
||||
url,
|
||||
undefined,
|
||||
config,
|
||||
);
|
||||
}
|
||||
|
||||
public connect<T extends Data>(
|
||||
public connect<TData = any>(
|
||||
url: string,
|
||||
config?: AxiosRequestConfig
|
||||
): Promise<AxiosResponse<T>> {
|
||||
return this._requestMethodWithoutParams<T>('connect', url, void 0, config);
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<TData>> {
|
||||
return this._requestMethodWithoutParams<TData>(
|
||||
'connect',
|
||||
url,
|
||||
undefined,
|
||||
config,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并配置后发送 HTTP 请求
|
||||
*
|
||||
* @param method 请求方法
|
||||
* @param url 请求地址
|
||||
* @param params 请求参数
|
||||
* @param config 额外配置
|
||||
*/
|
||||
private _requestMethodWithoutParams<T extends Data>(
|
||||
method: Method,
|
||||
private _requestMethodWithoutParams<TData = any>(
|
||||
method: AxiosRequestMethod,
|
||||
url: string,
|
||||
params?: Params,
|
||||
config: AxiosRequestConfig = {}
|
||||
): Promise<AxiosResponse<T>> {
|
||||
return this.request<T>({
|
||||
params?: AnyObject,
|
||||
config: AxiosRequestConfig = {},
|
||||
): Promise<AxiosResponse<TData>> {
|
||||
return this.request<TData>({
|
||||
...config,
|
||||
method,
|
||||
url,
|
||||
|
@ -133,21 +223,13 @@ export default class AxiosClass implements Axios {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并配置后发送 HTTP 请求
|
||||
*
|
||||
* @param method 请求方法
|
||||
* @param url 请求地址
|
||||
* @param data 请求数据
|
||||
* @param config 额外配置
|
||||
*/
|
||||
private _requestMethodWithoutData<T extends Data>(
|
||||
method: Method,
|
||||
private _requestMethodWithoutData<TData = any>(
|
||||
method: AxiosRequestMethod,
|
||||
url: string,
|
||||
data?: Data,
|
||||
config: AxiosRequestConfig = {}
|
||||
): Promise<AxiosResponse<T>> {
|
||||
return this.request<T>({
|
||||
data?: AnyObject,
|
||||
config: AxiosRequestConfig = {},
|
||||
): Promise<AxiosResponse<TData>> {
|
||||
return this.request<TData>({
|
||||
...config,
|
||||
method,
|
||||
url,
|
||||
|
|
|
@ -1,40 +1,45 @@
|
|||
import {
|
||||
InterceptorResolved,
|
||||
InterceptorRejected,
|
||||
Interceptor,
|
||||
InterceptorExecutor,
|
||||
InterceptorManager,
|
||||
} from '../types';
|
||||
export interface InterceptorResolved<T = any> {
|
||||
(value: T): T | Promise<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截器管理器
|
||||
*/
|
||||
export default class InterceptorManagerClass<T> implements InterceptorManager<T> {
|
||||
/**
|
||||
* 生成拦截器 id
|
||||
*/
|
||||
private _id = 0;
|
||||
export interface InterceptorRejected {
|
||||
(error: any): any | Promise<any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截器集合
|
||||
*/
|
||||
private _interceptors: Record<number, Interceptor<T>> = {};
|
||||
export interface Interceptor<T = any> {
|
||||
resolved: InterceptorResolved<T>;
|
||||
rejected?: InterceptorRejected;
|
||||
}
|
||||
|
||||
public use(resolved: InterceptorResolved<T>, rejected?: InterceptorRejected): number {
|
||||
this._interceptors[++this._id] = {
|
||||
export interface InterceptorExecutor {
|
||||
(interceptor: Interceptor): void;
|
||||
}
|
||||
|
||||
export default class InterceptorManager<T = any> {
|
||||
private id = 0;
|
||||
|
||||
private interceptors: AnyObject<Interceptor<T>> = {};
|
||||
|
||||
public use(
|
||||
resolved: InterceptorResolved,
|
||||
rejected?: InterceptorRejected,
|
||||
): number {
|
||||
this.interceptors[++this.id] = {
|
||||
resolved,
|
||||
rejected,
|
||||
};
|
||||
|
||||
return this._id;
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public eject(id: number): void {
|
||||
delete this._interceptors[id];
|
||||
delete this.interceptors[id];
|
||||
}
|
||||
|
||||
public forEach(executor: InterceptorExecutor<T>, reverse?: 'reverse'): void {
|
||||
let interceptors: Interceptor<T>[] = Object.values(this._interceptors);
|
||||
public forEach(executor: InterceptorExecutor, reverse?: 'reverse'): void {
|
||||
let interceptors: Interceptor[] = Object.keys(this.interceptors).map(
|
||||
(id) => this.interceptors[id],
|
||||
);
|
||||
|
||||
if (reverse === 'reverse') {
|
||||
interceptors = interceptors.reverse();
|
||||
|
|
|
@ -0,0 +1,270 @@
|
|||
import {
|
||||
assert,
|
||||
isEmptyArray,
|
||||
isPlainObject,
|
||||
isPlatform,
|
||||
isUndefined,
|
||||
revisePlatformApiNames,
|
||||
throwError,
|
||||
} from '../utils';
|
||||
import {
|
||||
AxiosProgressCallback,
|
||||
AxiosRequestConfig,
|
||||
AxiosRequestData,
|
||||
AxiosRequestFormData,
|
||||
AxiosRequestHeaders,
|
||||
AxiosResponse,
|
||||
AxiosResponseError,
|
||||
} from './Axios';
|
||||
|
||||
export type AdapterRequestMethod =
|
||||
| 'OPTIONS'
|
||||
| 'GET'
|
||||
| 'HEAD'
|
||||
| 'POST'
|
||||
| 'PUT'
|
||||
| 'DELETE'
|
||||
| 'TRACE'
|
||||
| 'CONNECT';
|
||||
|
||||
export type AdapterRequestType = 'request' | 'download' | 'upload';
|
||||
|
||||
export interface AxiosAdapterRequestConfig extends AxiosRequestConfig {
|
||||
type: AdapterRequestType;
|
||||
method: AdapterRequestMethod;
|
||||
url: string;
|
||||
success(response: AxiosResponse): void;
|
||||
fail(error: AxiosResponseError): void;
|
||||
}
|
||||
|
||||
export interface AxiosAdapterRequestOptions extends AxiosAdapterRequestConfig {
|
||||
header?: AxiosRequestHeaders;
|
||||
success(response: any): void;
|
||||
fail(error: any): void;
|
||||
}
|
||||
|
||||
export interface AxiosAdapterUploadOptions extends AxiosAdapterRequestOptions {
|
||||
filePath: string;
|
||||
name: string;
|
||||
fileName: string;
|
||||
fileType: 'image' | 'video' | 'audio';
|
||||
hideLoading?: boolean;
|
||||
formData?: AxiosRequestData;
|
||||
}
|
||||
|
||||
export interface AxiosAdapterDownloadOptions
|
||||
extends AxiosAdapterRequestOptions {
|
||||
filePath?: string;
|
||||
fileName?: string;
|
||||
}
|
||||
|
||||
export interface AxiosAdapterRequest {
|
||||
(config: AxiosAdapterRequestOptions): AxiosAdapterTask | void;
|
||||
}
|
||||
|
||||
export interface AxiosAdapterUpload {
|
||||
(config: AxiosAdapterUploadOptions): AxiosAdapterTask | void;
|
||||
}
|
||||
|
||||
export interface AxiosAdapterDownload {
|
||||
(config: AxiosAdapterDownloadOptions): AxiosAdapterTask | void;
|
||||
}
|
||||
export interface AxiosPlatform {
|
||||
request: AxiosAdapterRequest;
|
||||
upload: AxiosAdapterUpload;
|
||||
download: AxiosAdapterDownload;
|
||||
}
|
||||
|
||||
export interface AxiosAdapterTask {
|
||||
abort?(): void;
|
||||
onProgressUpdate?(callback: AxiosProgressCallback): void;
|
||||
offProgressUpdate?(callback: AxiosProgressCallback): void;
|
||||
}
|
||||
|
||||
export interface AxiosAdapter {
|
||||
(config: AxiosAdapterRequestConfig): AxiosAdapterTask | void;
|
||||
}
|
||||
|
||||
export function createAdapter(platform: AxiosPlatform): AxiosAdapter {
|
||||
assert(isPlainObject(platform), 'platform 需要是一个 Object 类型');
|
||||
assert(
|
||||
isPlatform(platform),
|
||||
'platform.request 与 platform.download 和 platform.upload 需要是一个 Function 类型',
|
||||
);
|
||||
|
||||
function transformCommon(common: any): void {
|
||||
if (!isUndefined(common.statusCode)) {
|
||||
common.status = common.statusCode;
|
||||
delete common.statusCode;
|
||||
}
|
||||
|
||||
if (isUndefined(common.status)) {
|
||||
common.status = isUndefined(common.data) ? 400 : 200;
|
||||
}
|
||||
|
||||
if (!isUndefined(common.header)) {
|
||||
common.headers = common.header;
|
||||
delete common.header;
|
||||
}
|
||||
|
||||
if (isUndefined(common.headers)) {
|
||||
common.headers = {};
|
||||
}
|
||||
|
||||
if (!isUndefined(common.errMsg)) {
|
||||
common.statusText = common.errMsg;
|
||||
delete common.errMsg;
|
||||
}
|
||||
|
||||
if (isUndefined(common.statusText)) {
|
||||
common.statusText =
|
||||
common.status === 200
|
||||
? 'OK'
|
||||
: common.status === 400
|
||||
? 'Bad Adapter'
|
||||
: '';
|
||||
}
|
||||
}
|
||||
|
||||
function generateDownloadResponseData(response: any): void {
|
||||
if (!isPlainObject(response.data)) {
|
||||
response.data = {};
|
||||
}
|
||||
|
||||
if (!isUndefined(response.tempFilePath)) {
|
||||
response.data.tempFilePath = response.tempFilePath;
|
||||
delete response.tempFilePath;
|
||||
}
|
||||
|
||||
if (!isUndefined(response.apFilePath)) {
|
||||
response.data.tempFilePath = response.apFilePath;
|
||||
delete response.apFilePath;
|
||||
}
|
||||
|
||||
if (!isUndefined(response.filePath)) {
|
||||
response.data.filePath = response.filePath;
|
||||
delete response.filePath;
|
||||
}
|
||||
}
|
||||
|
||||
function requestAdapter(
|
||||
request: AxiosAdapterRequest,
|
||||
config: AxiosAdapterRequestConfig,
|
||||
): AxiosAdapterTask | void {
|
||||
const options = Object.assign({}, config, {
|
||||
header: config.headers,
|
||||
success(response: any): void {
|
||||
transformCommon(response);
|
||||
config.success(response);
|
||||
},
|
||||
fail(error: any): void {
|
||||
transformCommon(error);
|
||||
config.fail(error);
|
||||
},
|
||||
});
|
||||
|
||||
return request(options);
|
||||
}
|
||||
|
||||
function uploadAdapter(
|
||||
upload: AxiosAdapterUpload,
|
||||
config: AxiosAdapterRequestConfig,
|
||||
): AxiosAdapterTask | void {
|
||||
const {
|
||||
fileName,
|
||||
filePath,
|
||||
fileType,
|
||||
hideLoading,
|
||||
...formData
|
||||
} = config.data as AxiosRequestFormData;
|
||||
const options = Object.assign({}, config, {
|
||||
header: config.headers,
|
||||
name: fileName,
|
||||
fileName: fileName,
|
||||
filePath,
|
||||
fileType: fileType ?? 'image',
|
||||
hideLoading,
|
||||
formData,
|
||||
success(response: any): void {
|
||||
transformCommon(response);
|
||||
config.success(response);
|
||||
},
|
||||
fail(error: any): void {
|
||||
transformCommon(error);
|
||||
config.fail(error);
|
||||
},
|
||||
});
|
||||
|
||||
return upload(options);
|
||||
}
|
||||
|
||||
function downloadAdapter(
|
||||
download: AxiosAdapterDownload,
|
||||
config: AxiosAdapterRequestConfig,
|
||||
): AxiosAdapterTask | void {
|
||||
const options = Object.assign({}, config, {
|
||||
header: config.headers,
|
||||
filePath: config.params?.filePath,
|
||||
fileName: config.params?.fileName,
|
||||
success(response: any): void {
|
||||
transformCommon(response);
|
||||
generateDownloadResponseData(response);
|
||||
config.success(response);
|
||||
},
|
||||
fail(error: any): void {
|
||||
transformCommon(error);
|
||||
config.fail(error);
|
||||
},
|
||||
});
|
||||
|
||||
return download(options);
|
||||
}
|
||||
|
||||
return function adapterDefault(
|
||||
config: AxiosAdapterRequestConfig,
|
||||
): AxiosAdapterTask | void {
|
||||
switch (config.type) {
|
||||
case 'request':
|
||||
return requestAdapter(platform.request, config);
|
||||
case 'upload':
|
||||
return uploadAdapter(platform.upload, config);
|
||||
case 'download':
|
||||
return downloadAdapter(platform.download, config);
|
||||
default:
|
||||
throwError(`无法识别的请求类型 ${config.type}`);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function getAdapterDefault(): AxiosAdapter | undefined {
|
||||
const tryGetPlatforms = [
|
||||
() => uni,
|
||||
() => wx,
|
||||
() => my,
|
||||
() => swan,
|
||||
() => tt,
|
||||
() => qq,
|
||||
() => qh,
|
||||
() => ks,
|
||||
() => dd,
|
||||
];
|
||||
|
||||
let platform;
|
||||
while (!isEmptyArray(tryGetPlatforms) && !isPlatform(platform)) {
|
||||
try {
|
||||
const tryGetPlatform = tryGetPlatforms.shift()!;
|
||||
|
||||
if (isPlainObject((platform = tryGetPlatform()))) {
|
||||
platform = revisePlatformApiNames(platform);
|
||||
}
|
||||
} catch (err) {
|
||||
// 避免出现异常导致程序被终止
|
||||
}
|
||||
}
|
||||
|
||||
if (!isPlatform(platform)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return createAdapter(platform);
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
export interface CancelAction {
|
||||
(message?: string): void;
|
||||
}
|
||||
|
||||
export interface CancelExecutor {
|
||||
(cancel: CancelAction): void;
|
||||
}
|
||||
|
||||
export interface CancelTokenSource {
|
||||
token: CancelToken;
|
||||
cancel: CancelAction;
|
||||
}
|
||||
|
||||
export interface CancelTokenConstructor {
|
||||
new (executor: CancelExecutor): CancelToken;
|
||||
source(): CancelTokenSource;
|
||||
}
|
||||
|
||||
export class Cancel {
|
||||
public message?: string;
|
||||
|
||||
public constructor(message?: string) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
const message = this.message ? `: ${this.message}` : '';
|
||||
|
||||
return `Cancel${message}`;
|
||||
}
|
||||
}
|
||||
|
||||
export function isCancel(value: any): value is Cancel {
|
||||
return value instanceof Cancel;
|
||||
}
|
||||
|
||||
export class CancelToken {
|
||||
private reason?: Cancel;
|
||||
|
||||
public listener: Promise<Cancel>;
|
||||
|
||||
public constructor(executor: CancelExecutor) {
|
||||
let action!: CancelAction;
|
||||
this.listener = new Promise<Cancel>((resolve) => {
|
||||
action = (message) => {
|
||||
if (this.reason) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.reason = new Cancel(message);
|
||||
|
||||
resolve(this.reason);
|
||||
};
|
||||
});
|
||||
|
||||
executor(action);
|
||||
}
|
||||
|
||||
public static source(): CancelTokenSource {
|
||||
let cancel!: CancelAction;
|
||||
const token = new CancelToken((action) => {
|
||||
cancel = action;
|
||||
});
|
||||
|
||||
return {
|
||||
token,
|
||||
cancel,
|
||||
};
|
||||
}
|
||||
|
||||
public throwIfRequested(): void {
|
||||
if (this.reason) {
|
||||
throw this.reason;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function isCancelToken(value: any): value is CancelToken {
|
||||
return value instanceof CancelToken;
|
||||
}
|
|
@ -1,45 +1,38 @@
|
|||
import { AxiosRequestConfig, RequestConfig, AxiosResponse, AxiosError } from '../types';
|
||||
import { AxiosAdapterRequestConfig } from './adapter';
|
||||
import { AxiosRequestConfig, AxiosResponse, AxiosResponseError } from './Axios';
|
||||
|
||||
/**
|
||||
* AxiosError 继承自 Error
|
||||
*/
|
||||
class AxiosErrorClass extends Error implements AxiosError {
|
||||
export type AxiosErrorResponse = AxiosResponse | AxiosResponseError;
|
||||
|
||||
class AxiosError extends Error {
|
||||
public isAxiosError = true;
|
||||
|
||||
/**
|
||||
* @param message 错误信息
|
||||
* @param config Axios 请求配置
|
||||
* @param request 通用请求配置
|
||||
* @param response Axios 响应体
|
||||
*/
|
||||
public config: AxiosRequestConfig;
|
||||
|
||||
public request: AxiosAdapterRequestConfig;
|
||||
|
||||
public response?: AxiosErrorResponse;
|
||||
|
||||
public constructor(
|
||||
message: string,
|
||||
public config: AxiosRequestConfig,
|
||||
public request: RequestConfig,
|
||||
public response?: AxiosResponse
|
||||
config: AxiosRequestConfig,
|
||||
request: AxiosAdapterRequestConfig,
|
||||
response?: AxiosErrorResponse,
|
||||
) {
|
||||
super(message);
|
||||
|
||||
// 修复继承系统自带类 prototype 设置失败的问题
|
||||
Object.setPrototypeOf(this, AxiosErrorClass.prototype);
|
||||
this.config = config;
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
|
||||
Object.setPrototypeOf(this, AxiosError.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 AxiosError 的工厂方法
|
||||
*
|
||||
* 返回一个新的 AxiosError 对象
|
||||
*
|
||||
* @param message 错误信息
|
||||
* @param config Axios 请求配置
|
||||
* @param request 通用请求配置
|
||||
* @param response Axios 响应体
|
||||
*/
|
||||
export default function createError(
|
||||
export function createError(
|
||||
message: string,
|
||||
config: AxiosRequestConfig,
|
||||
request: RequestConfig,
|
||||
response?: AxiosResponse
|
||||
request: AxiosAdapterRequestConfig,
|
||||
response?: AxiosErrorResponse,
|
||||
): AxiosError {
|
||||
return new AxiosErrorClass(message, config, request, response);
|
||||
return new AxiosError(message, config, request, response);
|
||||
}
|
||||
|
|
|
@ -1,55 +1,56 @@
|
|||
import { AxiosRequestConfig, AxiosResponse } from '../types';
|
||||
import isCancel from '../cancel/isCancel';
|
||||
import flattenHeaders from './flattenHeaders';
|
||||
import transformData from './transformData';
|
||||
import request from './request';
|
||||
import { isPlainObject } from '../utils';
|
||||
import { isCancel } from './cancel';
|
||||
import { flattenHeaders } from './flattenHeaders';
|
||||
import { transformData } from './transformData';
|
||||
import { request } from './request';
|
||||
import { AxiosRequestConfig, AxiosResponse } from './Axios';
|
||||
import { transformURL } from './transformURL';
|
||||
|
||||
/**
|
||||
* 如果已经取消, 则抛出取消对象
|
||||
*
|
||||
* @param config Axios 请求配置
|
||||
*/
|
||||
function throwIfCancellationRequested(config: AxiosRequestConfig) {
|
||||
if (config.cancelToken) {
|
||||
config.cancelToken.throwIfRequested();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送请求
|
||||
*
|
||||
* @param config Axios 请求配置
|
||||
*/
|
||||
export default function dispatchRequest(config: AxiosRequestConfig): Promise<AxiosResponse> {
|
||||
export default function dispatchRequest<TData = any>(
|
||||
config: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse> {
|
||||
throwIfCancellationRequested(config);
|
||||
|
||||
config.url = transformURL(config);
|
||||
config.headers = flattenHeaders(config);
|
||||
config.data = transformData(
|
||||
config.data,
|
||||
config.headers,
|
||||
config.transformRequest,
|
||||
);
|
||||
|
||||
config.data = transformData(config.data ?? {}, config.headers, config.transformRequest);
|
||||
|
||||
function onResolved(response: AxiosResponse): AxiosResponse {
|
||||
throwIfCancellationRequested(config);
|
||||
|
||||
response.data = transformData(response.data, response.headers, config.transformResponse);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
function onRejected(reason: any): Promise<any> {
|
||||
if (!isCancel(reason)) {
|
||||
return request<TData>(config).then(
|
||||
(response: AxiosResponse<TData>): AxiosResponse<TData> => {
|
||||
throwIfCancellationRequested(config);
|
||||
|
||||
if (reason.response !== void 0) {
|
||||
reason.response.data = transformData(
|
||||
reason.response.data,
|
||||
reason.response.headers,
|
||||
config.transformResponse
|
||||
);
|
||||
response.data = transformData(
|
||||
response.data,
|
||||
response.headers,
|
||||
config.transformResponse,
|
||||
) as TData;
|
||||
|
||||
return response;
|
||||
},
|
||||
(reason: any): Promise<any> => {
|
||||
if (!isCancel(reason)) {
|
||||
throwIfCancellationRequested(config);
|
||||
|
||||
if (isPlainObject(reason.response)) {
|
||||
reason.response.data = transformData(
|
||||
reason.response.data,
|
||||
reason.response.headers,
|
||||
config.transformResponse,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return config.errorHandler?.(reason) ?? Promise.reject(reason);
|
||||
}
|
||||
|
||||
return request(config).then(onResolved, onRejected);
|
||||
return config.errorHandler?.(reason) ?? Promise.reject(reason);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,35 +1,34 @@
|
|||
import { Headers, AxiosRequestConfig } from '../types';
|
||||
import { isUndefined, omit } from '../helpers/utils';
|
||||
import { methodToLowercase } from './transformMethod';
|
||||
import { isPlainObject, omit } from '../utils';
|
||||
import {
|
||||
AxiosRequestConfig,
|
||||
AxiosRequestMethodAlias,
|
||||
AxiosRequestHeaders,
|
||||
} from './Axios';
|
||||
|
||||
/**
|
||||
* 拉平请求头
|
||||
*
|
||||
* @param config Axios 请求配置
|
||||
*/
|
||||
export default function flattenHeaders(config: AxiosRequestConfig): Headers {
|
||||
const { headers } = config;
|
||||
|
||||
if (isUndefined(headers)) {
|
||||
return {};
|
||||
export function flattenHeaders(
|
||||
config: AxiosRequestConfig,
|
||||
): AxiosRequestHeaders | undefined {
|
||||
if (!isPlainObject(config.headers)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const method = methodToLowercase(config.method);
|
||||
const common = 'common';
|
||||
const method = config.method?.toLowerCase() ?? 'get';
|
||||
const alias: AxiosRequestMethodAlias[] = [
|
||||
'options',
|
||||
'get',
|
||||
'head',
|
||||
'post',
|
||||
'put',
|
||||
'delete',
|
||||
'trace',
|
||||
'connect',
|
||||
];
|
||||
|
||||
return {
|
||||
...(headers.common ?? {}),
|
||||
...(headers[method] ?? {}),
|
||||
...omit(
|
||||
headers,
|
||||
'common',
|
||||
'options',
|
||||
'get',
|
||||
'head',
|
||||
'post',
|
||||
'put',
|
||||
'delete',
|
||||
'trace',
|
||||
'connect'
|
||||
),
|
||||
};
|
||||
return Object.assign(
|
||||
{},
|
||||
config.headers[common],
|
||||
config.headers[method],
|
||||
omit(config.headers, common, ...alias),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
import { isPlainObject, isString } from '../utils';
|
||||
import { AdapterRequestType } from './adapter';
|
||||
import { AxiosRequestConfig } from './Axios';
|
||||
|
||||
function isUpload(config: AxiosRequestConfig): boolean {
|
||||
if (
|
||||
!isString(config.method) ||
|
||||
!isPlainObject(config.headers) ||
|
||||
!isPlainObject(config.data)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const method = config.method.toLowerCase();
|
||||
const contentType =
|
||||
config.headers['Content-Type'] ?? config.headers['content-type'];
|
||||
|
||||
return (
|
||||
method === 'post' &&
|
||||
/multipart\/form-data/.test(contentType) &&
|
||||
isString(config.data.fileName) &&
|
||||
isString(config.data.filePath)
|
||||
);
|
||||
}
|
||||
|
||||
function isDownload(config: AxiosRequestConfig): boolean {
|
||||
const method = config.method?.toLowerCase() ?? 'get';
|
||||
|
||||
return method === 'get' && config.responseType === 'file';
|
||||
}
|
||||
|
||||
export function generateType(config: AxiosRequestConfig): AdapterRequestType {
|
||||
let requestType: AdapterRequestType = 'request';
|
||||
|
||||
if (isUpload(config)) {
|
||||
requestType = 'upload';
|
||||
}
|
||||
|
||||
if (isDownload(config)) {
|
||||
requestType = 'download';
|
||||
}
|
||||
|
||||
return requestType;
|
||||
}
|
|
@ -1,122 +1,87 @@
|
|||
import { AnyObject, AxiosRequestConfig } from '../types';
|
||||
import { isPlainObject, deepMerge } from '../helpers/utils';
|
||||
import { isPlainObject, deepMerge, isUndefined } from '../utils';
|
||||
import { AxiosRequestConfig } from './Axios';
|
||||
|
||||
type OnlyFromConfig2Key = 'url' | 'data';
|
||||
type PriorityFromConfig2Key =
|
||||
| 'adapter'
|
||||
| 'baseURL'
|
||||
| 'method'
|
||||
| 'validateStatus'
|
||||
| 'paramsSerializer'
|
||||
| 'transformRequest'
|
||||
| 'transformResponse'
|
||||
| 'errorHandler'
|
||||
| 'cancelToken'
|
||||
| 'dataType'
|
||||
| 'responseType'
|
||||
| 'timeout'
|
||||
| 'enableHttp2'
|
||||
| 'enableQuic'
|
||||
| 'enableCache'
|
||||
| 'sslVerify';
|
||||
type DeepMergeConfigKey = 'params' | 'headers';
|
||||
type AxiosRequestConfigKey = keyof AxiosRequestConfig;
|
||||
|
||||
/**
|
||||
* 只取 config2 中的配置
|
||||
*
|
||||
* @param keys
|
||||
* @param config
|
||||
* @param config2
|
||||
*/
|
||||
function onlyFromConfig2(
|
||||
keys: OnlyFromConfig2Key[],
|
||||
config: AxiosRequestConfig,
|
||||
config2: AxiosRequestConfig
|
||||
keys: AxiosRequestConfigKey[],
|
||||
target: AxiosRequestConfig,
|
||||
config2: AxiosRequestConfig,
|
||||
) {
|
||||
keys.forEach((key) => {
|
||||
if (config2[key] !== void 0) {
|
||||
config[key] = config2[key] as any;
|
||||
const value = config2[key];
|
||||
|
||||
if (!isUndefined(value)) {
|
||||
target[key] = value as any;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 优先取 config2 中的配置, config2 中没有就取 config1
|
||||
*
|
||||
* @param keys
|
||||
* @param config
|
||||
* @param config1
|
||||
* @param config2
|
||||
*/
|
||||
function priorityFromConfig2(
|
||||
keys: PriorityFromConfig2Key[],
|
||||
config: AxiosRequestConfig,
|
||||
keys: AxiosRequestConfigKey[],
|
||||
target: AxiosRequestConfig,
|
||||
config1: AxiosRequestConfig,
|
||||
config2: AxiosRequestConfig
|
||||
config2: AxiosRequestConfig,
|
||||
) {
|
||||
keys.forEach((key) => {
|
||||
if (config2[key] !== void 0) {
|
||||
config[key] = config2[key] as any;
|
||||
} else if (config1[key] !== void 0) {
|
||||
config[key] = config1[key] as any;
|
||||
const value1 = config1[key];
|
||||
const value2 = config2[key];
|
||||
|
||||
if (!isUndefined(value2)) {
|
||||
target[key] = value2 as any;
|
||||
} else if (!isUndefined(value1)) {
|
||||
target[key] = value1 as any;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 深度合并配置
|
||||
*
|
||||
* @param keys
|
||||
* @param config
|
||||
* @param config1
|
||||
* @param config2
|
||||
*/
|
||||
function deepMergeConfig(
|
||||
keys: DeepMergeConfigKey[],
|
||||
config: AxiosRequestConfig,
|
||||
keys: AxiosRequestConfigKey[],
|
||||
target: AxiosRequestConfig,
|
||||
config1: AxiosRequestConfig,
|
||||
config2: AxiosRequestConfig
|
||||
config2: AxiosRequestConfig,
|
||||
) {
|
||||
keys.forEach((key) => {
|
||||
if (isPlainObject(config2[key])) {
|
||||
config[key] = deepMerge<AnyObject>(config1[key] ?? {}, config2[key] as AnyObject);
|
||||
} else if (isPlainObject(config1[key])) {
|
||||
config[key] = deepMerge<AnyObject>(config1[key] as AnyObject);
|
||||
const value1 = config1[key];
|
||||
const value2 = config2[key];
|
||||
|
||||
if (isPlainObject(value2)) {
|
||||
target[key] = deepMerge(value1 ?? {}, value2) as any;
|
||||
} else if (isPlainObject(value1)) {
|
||||
target[key] = deepMerge(value1) as any;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并 Axios 请求配置
|
||||
*
|
||||
* @param config1 Axios 请求配置1
|
||||
* @param config2 Axios 请求配置2
|
||||
*/
|
||||
export default function mergeConfig(
|
||||
const onlyFromConfig2Keys: AxiosRequestConfigKey[] = ['url', 'method', 'data'];
|
||||
const priorityFromConfig2Keys: AxiosRequestConfigKey[] = [
|
||||
'adapter',
|
||||
'baseURL',
|
||||
'method',
|
||||
'validateStatus',
|
||||
'paramsSerializer',
|
||||
'transformRequest',
|
||||
'transformResponse',
|
||||
'errorHandler',
|
||||
'cancelToken',
|
||||
'dataType',
|
||||
'responseType',
|
||||
'timeout',
|
||||
'enableHttp2',
|
||||
'enableQuic',
|
||||
'enableCache',
|
||||
'sslVerify',
|
||||
'validateStatus',
|
||||
'onUploadProgress',
|
||||
'onDownloadProgress',
|
||||
];
|
||||
const deepMergeConfigKeys: AxiosRequestConfigKey[] = ['headers', 'params'];
|
||||
|
||||
export function mergeConfig(
|
||||
config1: AxiosRequestConfig = {},
|
||||
config2: AxiosRequestConfig = {}
|
||||
config2: AxiosRequestConfig = {},
|
||||
): AxiosRequestConfig {
|
||||
const config: AxiosRequestConfig = {};
|
||||
const onlyFromConfig2Keys: OnlyFromConfig2Key[] = ['url', 'data'];
|
||||
const priorityFromConfig2Keys: PriorityFromConfig2Key[] = [
|
||||
'adapter',
|
||||
'baseURL',
|
||||
'method',
|
||||
'validateStatus',
|
||||
'paramsSerializer',
|
||||
'transformRequest',
|
||||
'transformResponse',
|
||||
'errorHandler',
|
||||
'cancelToken',
|
||||
'dataType',
|
||||
'responseType',
|
||||
'timeout',
|
||||
'enableHttp2',
|
||||
'enableQuic',
|
||||
'enableCache',
|
||||
'sslVerify',
|
||||
];
|
||||
const deepMergeConfigKeys: DeepMergeConfigKey[] = ['headers', 'params'];
|
||||
|
||||
onlyFromConfig2(onlyFromConfig2Keys, config, config2);
|
||||
priorityFromConfig2(priorityFromConfig2Keys, config, config1, config2);
|
||||
|
|
|
@ -1,67 +1,74 @@
|
|||
import { AxiosRequestConfig, AxiosResponse, Response } from '../types';
|
||||
import { isString, isUndefined } from '../helpers/utils';
|
||||
import transformRequest from './transformRequest';
|
||||
import transformResponse from './transformResponse';
|
||||
import createError from './createError';
|
||||
import { assert, isFunction, isPlainObject } from '../utils';
|
||||
import { AxiosAdapterRequestConfig, AdapterRequestMethod } from './adapter';
|
||||
import { AxiosRequestConfig, AxiosResponse, AxiosResponseError } from './Axios';
|
||||
import { isCancelToken } from './cancel';
|
||||
import { AxiosErrorResponse, createError } from './createError';
|
||||
import { generateType } from './generateType';
|
||||
|
||||
/**
|
||||
* 请求函数
|
||||
*
|
||||
* @param config Axios 请求配置
|
||||
*/
|
||||
export default function request(config: AxiosRequestConfig): Promise<AxiosResponse> {
|
||||
return new Promise(function dispatchAdapter(resolve, reject): void {
|
||||
const { adapter, cancelToken } = config;
|
||||
const requestConfig = transformRequest(config);
|
||||
|
||||
/**
|
||||
* 捕获错误
|
||||
*
|
||||
* @param message 错误信息
|
||||
* @param response Axios 响应体
|
||||
*/
|
||||
function catchError(message: any, response?: AxiosResponse): void {
|
||||
if (!isString(message)) {
|
||||
message = message.fail;
|
||||
}
|
||||
|
||||
reject(createError(message, config, requestConfig, response));
|
||||
function tryToggleProgressUpdate(
|
||||
adapterConfig: AxiosAdapterRequestConfig,
|
||||
progressUpdate?: Function,
|
||||
) {
|
||||
if (isFunction(progressUpdate)) {
|
||||
switch (adapterConfig.type) {
|
||||
case 'upload':
|
||||
if (isFunction(adapterConfig.onUploadProgress)) {
|
||||
progressUpdate(adapterConfig.onUploadProgress);
|
||||
}
|
||||
break;
|
||||
case 'download':
|
||||
if (isFunction(adapterConfig.onDownloadProgress)) {
|
||||
progressUpdate(adapterConfig.onDownloadProgress);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isUndefined(adapter)) {
|
||||
catchError('平台适配失败,您需要参阅文档使用自定义适配器手动适配当前平台');
|
||||
export function request<TData = any>(
|
||||
config: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<TData>> {
|
||||
return new Promise((resolve, reject) => {
|
||||
assert(isFunction(config.adapter), 'adapter 需要是一个 Function 类型');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 效验状态码
|
||||
*
|
||||
* @param res 请求结果
|
||||
*/
|
||||
function handleResponse(res: Response): void {
|
||||
const response = transformResponse(res, config);
|
||||
|
||||
if (isUndefined(config.validateStatus) || config.validateStatus(response.status)) {
|
||||
resolve(response);
|
||||
} else {
|
||||
catchError(`请求失败,状态码为 ${response.status}`, response);
|
||||
}
|
||||
}
|
||||
|
||||
// 使用适配器发送请求
|
||||
const task = adapter({
|
||||
...requestConfig,
|
||||
success: handleResponse,
|
||||
fail: catchError,
|
||||
const adapterConfig: AxiosAdapterRequestConfig = Object.assign({}, config, {
|
||||
url: config.url ?? '',
|
||||
type: generateType(config),
|
||||
method: (config.method?.toUpperCase() as AdapterRequestMethod) ?? 'GET',
|
||||
success(response: AxiosResponse): void {
|
||||
if (
|
||||
!isFunction(config.validateStatus) ||
|
||||
config.validateStatus(response.status)
|
||||
) {
|
||||
resolve(response);
|
||||
} else {
|
||||
catchError('请求失败', response);
|
||||
}
|
||||
},
|
||||
fail(error: AxiosResponseError): void {
|
||||
catchError('网络错误', error);
|
||||
},
|
||||
});
|
||||
|
||||
// 如果存在取消令牌
|
||||
// 则调用取消令牌里的 listener 监听用户的取消操作
|
||||
if (!isUndefined(cancelToken)) {
|
||||
cancelToken.listener.then(function onCanceled(reason): void {
|
||||
if (!isUndefined(task)) {
|
||||
task.abort();
|
||||
function catchError(message: string, response?: AxiosErrorResponse): void {
|
||||
reject(createError(message, config, adapterConfig, response));
|
||||
}
|
||||
|
||||
const adapterTask = config.adapter!(adapterConfig);
|
||||
|
||||
if (isPlainObject(adapterTask)) {
|
||||
tryToggleProgressUpdate(adapterConfig, adapterTask.onProgressUpdate);
|
||||
}
|
||||
|
||||
if (isCancelToken(config.cancelToken)) {
|
||||
config.cancelToken.listener.then((reason: any) => {
|
||||
if (isPlainObject(adapterTask)) {
|
||||
tryToggleProgressUpdate(adapterConfig, adapterTask.offProgressUpdate);
|
||||
|
||||
if (isFunction(adapterTask.abort)) {
|
||||
adapterTask.abort();
|
||||
}
|
||||
}
|
||||
|
||||
reject(reason);
|
||||
|
|
|
@ -1,27 +1,31 @@
|
|||
import { Data, Headers, TransformData } from '../types';
|
||||
import { isUndefined } from '../helpers/utils';
|
||||
import { isArray, isUndefined } from '../utils';
|
||||
import {
|
||||
AxiosRequestData,
|
||||
AxiosRequestFormData,
|
||||
AxiosResponseHeaders,
|
||||
} from './Axios';
|
||||
|
||||
/**
|
||||
* 转换数据
|
||||
*
|
||||
* @param data 请求数据/响应数据
|
||||
* @param headers 请求头/响应头
|
||||
* @param transforms 请求数据转换函数/响应数据转换函数
|
||||
*/
|
||||
export default function transformData(
|
||||
data: Data,
|
||||
headers: Headers,
|
||||
transforms?: TransformData | TransformData[]
|
||||
): Data {
|
||||
export interface AxiosTransformer {
|
||||
(
|
||||
data?: AxiosRequestData | AxiosRequestFormData,
|
||||
headers?: AxiosResponseHeaders,
|
||||
): AxiosRequestData | AxiosRequestFormData;
|
||||
}
|
||||
|
||||
export function transformData(
|
||||
data?: AxiosRequestData | AxiosRequestFormData,
|
||||
headers?: AxiosResponseHeaders,
|
||||
transforms?: AxiosTransformer | AxiosTransformer[],
|
||||
): AxiosRequestData | AxiosRequestFormData | undefined {
|
||||
if (isUndefined(transforms)) {
|
||||
return data;
|
||||
}
|
||||
|
||||
if (!Array.isArray(transforms)) {
|
||||
if (!isArray(transforms)) {
|
||||
transforms = [transforms];
|
||||
}
|
||||
|
||||
transforms.forEach((transform: TransformData) => {
|
||||
transforms.forEach((transform: AxiosTransformer) => {
|
||||
data = transform(data, headers);
|
||||
});
|
||||
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
import { AliasMethod, AdapterMethod, Method } from '../types';
|
||||
|
||||
/**
|
||||
* 请求方法转全小写
|
||||
*
|
||||
* @param config Axios 请求配置
|
||||
*/
|
||||
export function methodToLowercase(method: Method = 'get'): AliasMethod {
|
||||
return method.toLowerCase() as AliasMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求方法转全大写
|
||||
*
|
||||
* @param config Axios 请求配置
|
||||
*/
|
||||
export function methodToUppercase(method: Method = 'GET'): AdapterMethod {
|
||||
return method.toUpperCase() as AdapterMethod;
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
import { AxiosRequestConfig, RequestConfig } from '../types';
|
||||
import { pick } from '../helpers/utils';
|
||||
import isAbsoluteURL from '../helpers/isAbsoluteURL';
|
||||
import combineURL from '../helpers/combineURL';
|
||||
import dynamicURL from 'src/helpers/dynamicURL';
|
||||
import buildURL from '../helpers/buildURL';
|
||||
import { methodToUppercase } from './transformMethod';
|
||||
|
||||
/**
|
||||
* 根据配置中的 baseURL 和 url 和 params 生成完整 URL
|
||||
*
|
||||
* @param config Axios 请求配置
|
||||
*/
|
||||
function transformURL(config: AxiosRequestConfig): string {
|
||||
const { baseURL = '', params } = config;
|
||||
let { url = '' } = config;
|
||||
|
||||
url = isAbsoluteURL(url) ? url : combineURL(baseURL, url);
|
||||
url = dynamicURL(url, params);
|
||||
return buildURL(url, config.params, config.paramsSerializer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Axios 请求配置转换成各大平台通用请求配置
|
||||
*
|
||||
* 抹平差异
|
||||
*
|
||||
* @param config Axios 请求配置
|
||||
*/
|
||||
export default function transformRequest(
|
||||
config: AxiosRequestConfig,
|
||||
): RequestConfig {
|
||||
return {
|
||||
url: transformURL(config),
|
||||
|
||||
method: methodToUppercase(config.method),
|
||||
|
||||
header: config.headers,
|
||||
|
||||
...pick(
|
||||
config,
|
||||
'data',
|
||||
'headers',
|
||||
'dataType',
|
||||
'responseType',
|
||||
'timeout',
|
||||
'enableHttp2',
|
||||
'enableQuic',
|
||||
'enableCache',
|
||||
'sslVerify',
|
||||
),
|
||||
} as RequestConfig;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
import { AxiosRequestConfig, AxiosResponse, Response } from '../types';
|
||||
import { pick } from '../helpers/utils';
|
||||
|
||||
/**
|
||||
* 各大平台通用响应体转成 Axios 响应体
|
||||
*
|
||||
* 抹平差异
|
||||
*
|
||||
* @param response 通用响应体
|
||||
* @param config Axios 请求配置
|
||||
*/
|
||||
export default function transformResponse(
|
||||
response: Response,
|
||||
config: AxiosRequestConfig
|
||||
): AxiosResponse {
|
||||
const status = response.statusCode ?? response.status ?? 400;
|
||||
|
||||
const headers = response.header ?? response.headers ?? {};
|
||||
|
||||
const statusText = status === 200 ? 'OK' : status === 400 ? 'Bad Adapter' : '';
|
||||
|
||||
return {
|
||||
status,
|
||||
statusText,
|
||||
headers,
|
||||
config,
|
||||
...pick(response, 'data', 'cookies', 'profile'),
|
||||
};
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import { buildURL, combineURL, dynamicURL, isAbsoluteURL } from '../utils';
|
||||
import { AxiosRequestConfig } from './Axios';
|
||||
|
||||
export function transformURL(config: AxiosRequestConfig): string {
|
||||
let url = config.url ?? '';
|
||||
|
||||
if (!isAbsoluteURL(url)) {
|
||||
url = combineURL(config.baseURL, url);
|
||||
}
|
||||
|
||||
url = dynamicURL(url, config.params);
|
||||
url = buildURL(url, config.params, config.paramsSerializer);
|
||||
|
||||
return url;
|
||||
}
|
|
@ -1,20 +1,9 @@
|
|||
import { AxiosRequestConfig } from './types';
|
||||
import adaptive from './adaptive';
|
||||
import { getAdapterDefault } from './core/adapter';
|
||||
import { AxiosRequestConfig } from './core/Axios';
|
||||
|
||||
const defaults: AxiosRequestConfig = {
|
||||
/**
|
||||
* 适配器
|
||||
*/
|
||||
adapter: adaptive(),
|
||||
|
||||
/**
|
||||
* 请求方法
|
||||
*/
|
||||
adapter: getAdapterDefault(),
|
||||
method: 'get',
|
||||
|
||||
/**
|
||||
* 请求头
|
||||
*/
|
||||
headers: {
|
||||
common: {
|
||||
Accept: 'application/json, test/plain, */*',
|
||||
|
@ -32,49 +21,15 @@ const defaults: AxiosRequestConfig = {
|
|||
trace: {},
|
||||
connect: {},
|
||||
},
|
||||
|
||||
/**
|
||||
* 状态码效验
|
||||
*
|
||||
* @param status 状态码
|
||||
*/
|
||||
validateStatus: function validateStatus(status: number): boolean {
|
||||
validateStatus(status: number): boolean {
|
||||
return status >= 200 && status < 300;
|
||||
},
|
||||
|
||||
/**
|
||||
* 超时时间
|
||||
*/
|
||||
timeout: 10000,
|
||||
|
||||
/**
|
||||
* 响应数据格式
|
||||
*/
|
||||
dataType: 'json',
|
||||
|
||||
/**
|
||||
* 响应数据类型
|
||||
*/
|
||||
responseType: 'text',
|
||||
|
||||
/**
|
||||
* 开启 http2
|
||||
*/
|
||||
enableHttp2: false,
|
||||
|
||||
/**
|
||||
* 开启 quic
|
||||
*/
|
||||
enableQuic: false,
|
||||
|
||||
/**
|
||||
* 开启 cache
|
||||
*/
|
||||
enableCache: false,
|
||||
|
||||
/**
|
||||
* 验证 ssl 证书
|
||||
*/
|
||||
sslVerify: true,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
import { AnyObject, Params } from '../types';
|
||||
import { encode, isPlainObject, isDate, isUndefined, isNull } from './utils';
|
||||
|
||||
/**
|
||||
* 通过请求地址和序列化参数生成新的请求地址
|
||||
*
|
||||
* @param url 请求地址
|
||||
* @param serializedParams 序列化参数
|
||||
*/
|
||||
function generateURL(url: string, serializedParams: string): string {
|
||||
// 移除 hash
|
||||
const hashIndex = url.indexOf('#');
|
||||
|
||||
if (hashIndex !== -1) {
|
||||
url = url.slice(0, hashIndex);
|
||||
}
|
||||
|
||||
if (serializedParams === '') {
|
||||
return url;
|
||||
}
|
||||
|
||||
// 拼接前缀
|
||||
const prefix = url.indexOf('?') === -1 ? '?' : '&';
|
||||
|
||||
serializedParams = `${prefix}${serializedParams}`;
|
||||
|
||||
return `${url}${serializedParams}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认参数序列化
|
||||
*
|
||||
* @param params 请求参数
|
||||
*/
|
||||
function paramsSerialization(params: AnyObject): string {
|
||||
const parts: string[] = [];
|
||||
|
||||
Object.entries(params).forEach(function encodeKeyValue([key, value]): void {
|
||||
if (isNull(value) || isUndefined(value) || value !== value) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果值是一个数组, 则特殊处理 key
|
||||
if (Array.isArray(value)) {
|
||||
key += '[]';
|
||||
}
|
||||
|
||||
// 转成数组统一处理
|
||||
const values: any[] = [].concat(value);
|
||||
|
||||
values.forEach((val: any): void => {
|
||||
if (isPlainObject(val)) {
|
||||
val = JSON.stringify(val);
|
||||
} else if (isDate(val)) {
|
||||
val = val.toISOString();
|
||||
}
|
||||
|
||||
parts.push(`${encode(key)}=${encode(val)}`);
|
||||
});
|
||||
});
|
||||
|
||||
return parts.join('&');
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 URL 参数
|
||||
*
|
||||
* @param url 请求地址
|
||||
* @param params 请求参数
|
||||
* @param paramsSerializer 自定义参数序列化
|
||||
*/
|
||||
export default function buildURL(
|
||||
url: string,
|
||||
params: Params = {},
|
||||
paramsSerializer = paramsSerialization
|
||||
): string {
|
||||
return generateURL(url, paramsSerializer(params));
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
/**
|
||||
* 拼接 baseURL 和 url 获得完整的 URL
|
||||
*
|
||||
* combineURL('1/2///','////3/4') => '1/2/3/4'
|
||||
*/
|
||||
export default function combineURL(baseURL: string, url: string): string {
|
||||
return `${baseURL.replace(/\/*$/, '')}/${url.replace(/^\/*/, '')}`;
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
import { Params } from '../types';
|
||||
import { isPlainObject } from './utils';
|
||||
|
||||
const dynamicREG = /\/?(:([a-zA-Z_$][\w-$]?))\/??/g;
|
||||
|
||||
export default function dynamicURL(url: string, params?: Params): string {
|
||||
if (!isPlainObject(params)) {
|
||||
return url;
|
||||
}
|
||||
|
||||
return url.replace(dynamicREG, (key1, key2, key3) =>
|
||||
key1.replace(key2, params[key3]),
|
||||
);
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
/**
|
||||
* 检查是否是一个绝对 URL
|
||||
*
|
||||
* xxx:// 或者 "//" 开头, 视为绝对地址
|
||||
*
|
||||
* @param url 需要检查的 URL
|
||||
*/
|
||||
export default function isAbsoluteURL(url: string): boolean {
|
||||
return /^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(url);
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
import { AnyObject, ObjectTree } from '../types';
|
||||
|
||||
const _toString = Object.prototype.toString;
|
||||
|
||||
/**
|
||||
* 对字符串进行编码转换
|
||||
*
|
||||
* @param str 字符串
|
||||
*/
|
||||
export function encode(str: string): string {
|
||||
return encodeURIComponent(str)
|
||||
.replace(/%40/gi, '@')
|
||||
.replace(/%3A/gi, ':')
|
||||
.replace(/%24/g, '$')
|
||||
.replace(/%2C/gi, ',')
|
||||
.replace(/%20/g, '+')
|
||||
.replace(/%5B/gi, '[')
|
||||
.replace(/%5D/gi, ']');
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是 Date
|
||||
*/
|
||||
export function isDate(date: unknown): date is Date {
|
||||
return _toString.call(date) === '[object Date]';
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是普通对象
|
||||
*/
|
||||
export function isPlainObject<T = never>(
|
||||
value: unknown
|
||||
): value is [T] extends never[] ? AnyObject : T {
|
||||
return _toString.call(value) === '[object Object]';
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是 undefined
|
||||
*/
|
||||
export function isUndefined(value: unknown): value is undefined {
|
||||
return typeof value === 'undefined';
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是字符型
|
||||
*/
|
||||
export function isString(value: unknown): value is number {
|
||||
return typeof value === 'string';
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是 Null
|
||||
*/
|
||||
export function isNull(value: unknown): value is null {
|
||||
return value === null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 深度合并多个对象
|
||||
*
|
||||
* @param objs n 个对象
|
||||
*/
|
||||
export function deepMerge<T = never>(...objs: ObjectTree[]): [T] extends never[] ? ObjectTree : T {
|
||||
const result: ObjectTree = {};
|
||||
|
||||
function assignValue(key: string, val: unknown) {
|
||||
// 如果当前结果和当前值都为普通对象
|
||||
// 递归进行深度合并
|
||||
if (isPlainObject(result[key]) && isPlainObject(val)) {
|
||||
result[key] = deepMerge(result[key] as ObjectTree, val as ObjectTree);
|
||||
}
|
||||
// 如果只有当前值为普通对象
|
||||
// 直接深拷贝当前值
|
||||
else if (isPlainObject(val)) {
|
||||
result[key] = deepMerge({}, val as ObjectTree);
|
||||
}
|
||||
// 如果都不是普通对象
|
||||
// 直接赋值
|
||||
else {
|
||||
result[key] = val;
|
||||
}
|
||||
}
|
||||
|
||||
objs.forEach(function assignObj(obj: ObjectTree): void {
|
||||
Object.entries(obj).forEach(function ([key, value]) {
|
||||
assignValue(key, value);
|
||||
});
|
||||
});
|
||||
|
||||
return result as [T] extends never[] ? ObjectTree : T;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从对象中提取一部分属性
|
||||
*
|
||||
* @param obj 源对象
|
||||
* @param keys 需要提取的 key
|
||||
*/
|
||||
export function pick<T extends AnyObject, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K> {
|
||||
const _pick: Partial<T> = {};
|
||||
|
||||
keys.forEach(function pickKey(key: K) {
|
||||
_pick[key] = obj[key];
|
||||
});
|
||||
|
||||
return _pick as Pick<T, K>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从对象中剔除一部分属性
|
||||
*
|
||||
* @param obj 源对象
|
||||
* @param keys 需要剔除的 key
|
||||
*/
|
||||
export function omit<T extends AnyObject, K extends keyof T>(obj: T, ...keys: K[]): Omit<T, K> {
|
||||
const _omit = { ...obj };
|
||||
|
||||
keys.forEach(function omitKey(key: K) {
|
||||
delete _omit[key];
|
||||
});
|
||||
|
||||
return _omit;
|
||||
}
|
14
src/index.ts
14
src/index.ts
|
@ -1,5 +1,15 @@
|
|||
import axios from './axios';
|
||||
|
||||
export * from './types';
|
||||
|
||||
export {
|
||||
AxiosRequestConfig,
|
||||
AxiosRequestFormData,
|
||||
AxiosResponse,
|
||||
AxiosResponseError,
|
||||
} from './core/Axios';
|
||||
export {
|
||||
AxiosAdapterRequestConfig,
|
||||
AxiosAdapter,
|
||||
AxiosPlatform,
|
||||
} from './core/adapter';
|
||||
export { AxiosInstance, AxiosStatic } from './axios';
|
||||
export default axios;
|
||||
|
|
755
src/types.ts
755
src/types.ts
|
@ -1,755 +0,0 @@
|
|||
/**
|
||||
* 任意值对象
|
||||
*/
|
||||
export declare interface AnyObject<T extends any = any> {
|
||||
[x: string]: T;
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求方法
|
||||
*/
|
||||
export declare type AdapterMethod =
|
||||
| 'OPTIONS'
|
||||
| 'GET'
|
||||
| 'HEAD'
|
||||
| 'POST'
|
||||
| 'PUT'
|
||||
| 'DELETE'
|
||||
| 'TRACE'
|
||||
| 'CONNECT';
|
||||
|
||||
/**
|
||||
* 请求方法别名
|
||||
*/
|
||||
export declare type AliasMethod =
|
||||
| 'options'
|
||||
| 'get'
|
||||
| 'head'
|
||||
| 'post'
|
||||
| 'put'
|
||||
| 'delete'
|
||||
| 'trace'
|
||||
| 'connect';
|
||||
|
||||
/**
|
||||
* Axios 请求方法
|
||||
*/
|
||||
export declare type Method = AliasMethod | AdapterMethod;
|
||||
|
||||
/**
|
||||
* Axios 参数
|
||||
*/
|
||||
export declare type Params = AnyObject;
|
||||
|
||||
/**
|
||||
* Axios 数据
|
||||
*/
|
||||
export declare type Data = string | AnyObject | ArrayBuffer;
|
||||
|
||||
/**
|
||||
* Axios 头
|
||||
*/
|
||||
export declare interface Headers
|
||||
extends Partial<Record<'common' | AliasMethod, AnyObject<string>>> {
|
||||
/**
|
||||
* 自定义配置
|
||||
*/
|
||||
[x: string]: AnyObject<string> | string | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用请求配置
|
||||
*/
|
||||
export declare interface RequestConfig {
|
||||
/**
|
||||
* 接口地址
|
||||
*/
|
||||
url: string;
|
||||
|
||||
/**
|
||||
* HTTP 请求方法
|
||||
*/
|
||||
method: AdapterMethod;
|
||||
|
||||
/**
|
||||
* 请求数据
|
||||
*/
|
||||
data: Data;
|
||||
|
||||
/**
|
||||
* 请求头 同 headers
|
||||
*/
|
||||
header: AnyObject;
|
||||
|
||||
/**
|
||||
* 请求头 同 header
|
||||
*/
|
||||
headers: AnyObject;
|
||||
|
||||
/**
|
||||
* 返回的数据格式
|
||||
*/
|
||||
dataType?: 'json' | '其他';
|
||||
|
||||
/**
|
||||
* 响应的数据类型
|
||||
*/
|
||||
responseType?: 'text' | 'arraybuffer';
|
||||
|
||||
/**
|
||||
* 超时时间
|
||||
*/
|
||||
timeout?: number;
|
||||
|
||||
/**
|
||||
* 开启 http2
|
||||
*/
|
||||
enableHttp2?: boolean;
|
||||
|
||||
/**
|
||||
* 开启 quic
|
||||
*/
|
||||
enableQuic?: boolean;
|
||||
|
||||
/**
|
||||
* 开启 cache
|
||||
*/
|
||||
enableCache?: boolean;
|
||||
|
||||
/**
|
||||
* 验证 ssl 证书
|
||||
*/
|
||||
sslVerify?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用响应体
|
||||
*/
|
||||
export declare interface Response {
|
||||
/**
|
||||
* 响应状态码
|
||||
*/
|
||||
statusCode?: number;
|
||||
|
||||
/**
|
||||
* 响应状态码
|
||||
*/
|
||||
status?: number;
|
||||
|
||||
/**
|
||||
* 响应头 Headers
|
||||
*/
|
||||
header?: AnyObject;
|
||||
|
||||
/**
|
||||
* 响应头 Headers
|
||||
*/
|
||||
headers?: Headers;
|
||||
|
||||
/**
|
||||
* 响应数据
|
||||
*/
|
||||
data: Data;
|
||||
|
||||
/**
|
||||
* 开发者服务器返回的 cookies,格式为字符串数组
|
||||
*/
|
||||
cookies?: string[];
|
||||
|
||||
/**
|
||||
* 网络请求过程中一些关键时间点的耗时信息
|
||||
*/
|
||||
profile?: AnyObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 适配器请求配置
|
||||
*/
|
||||
export declare interface AdapterRequestConfig extends RequestConfig {
|
||||
/**
|
||||
* 成功的响应函数
|
||||
*/
|
||||
success: (res: Response) => void;
|
||||
|
||||
/**
|
||||
* 失败的响应函数
|
||||
*/
|
||||
fail: (err: unknown) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* 适配器请求任务
|
||||
*/
|
||||
export declare interface AdapterRequestTask {
|
||||
/**
|
||||
* 取消请求
|
||||
*/
|
||||
abort(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* 适配器
|
||||
*/
|
||||
export declare interface Adapter {
|
||||
(config: AdapterRequestConfig): AdapterRequestTask | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* 平台
|
||||
*/
|
||||
export declare interface Platform {
|
||||
request: Adapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换数据函数
|
||||
*/
|
||||
export declare interface TransformData {
|
||||
(data: Data, headers: Headers): Data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误处理程序
|
||||
*/
|
||||
export declare interface ErrorHandler {
|
||||
(error: any): Promise<any> | any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Axios 请求配置
|
||||
*/
|
||||
export declare interface AxiosRequestConfig {
|
||||
/**
|
||||
* 自定义适配器
|
||||
*/
|
||||
adapter?: Adapter;
|
||||
|
||||
/**
|
||||
* 基础地址
|
||||
*/
|
||||
baseURL?: string;
|
||||
|
||||
/**
|
||||
* 请求地址
|
||||
*/
|
||||
url?: string;
|
||||
|
||||
/**
|
||||
* 请求方法
|
||||
*/
|
||||
method?: Method;
|
||||
|
||||
/**
|
||||
* 请求参数
|
||||
*/
|
||||
params?: Params;
|
||||
|
||||
/**
|
||||
* 请求数据
|
||||
*/
|
||||
data?: Data;
|
||||
|
||||
/**
|
||||
* 请求头
|
||||
*/
|
||||
headers?: Headers;
|
||||
|
||||
/**
|
||||
* 自定义合法状态码
|
||||
*/
|
||||
validateStatus?: (status: number) => boolean;
|
||||
|
||||
/**
|
||||
* 自定义参数序列化
|
||||
*/
|
||||
paramsSerializer?: (params?: AnyObject) => string;
|
||||
|
||||
/**
|
||||
* 转换请求数据
|
||||
*/
|
||||
transformRequest?: TransformData | TransformData[];
|
||||
|
||||
/**
|
||||
* 转换响应数据
|
||||
*/
|
||||
transformResponse?: TransformData | TransformData[];
|
||||
|
||||
/**
|
||||
* 自定义错误处理
|
||||
*/
|
||||
errorHandler?: ErrorHandler;
|
||||
|
||||
/**
|
||||
* 取消令牌
|
||||
*/
|
||||
cancelToken?: CancelToken;
|
||||
|
||||
/**
|
||||
* 超时时间
|
||||
*/
|
||||
timeout?: number;
|
||||
|
||||
/**
|
||||
* 响应数据格式
|
||||
*/
|
||||
dataType?: 'json' | '其他';
|
||||
|
||||
/**
|
||||
* 响应数据类型
|
||||
*/
|
||||
responseType?: 'text' | 'arraybuffer';
|
||||
|
||||
/**
|
||||
* 开启 http2
|
||||
*/
|
||||
enableHttp2?: boolean;
|
||||
|
||||
/**
|
||||
* 开启 quic
|
||||
*/
|
||||
enableQuic?: boolean;
|
||||
|
||||
/**
|
||||
* 开启 cache
|
||||
*/
|
||||
enableCache?: boolean;
|
||||
|
||||
/**
|
||||
* 验证 ssl 证书
|
||||
*/
|
||||
sslVerify?: boolean;
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Axios 响应体
|
||||
*/
|
||||
export declare interface AxiosResponse<T extends Data = Data> {
|
||||
/**
|
||||
* 状态码
|
||||
*/
|
||||
status: number;
|
||||
|
||||
/**
|
||||
* 状态文本
|
||||
*/
|
||||
statusText: string;
|
||||
|
||||
/**
|
||||
* 服务端返回的数据
|
||||
*/
|
||||
data: T;
|
||||
|
||||
/**
|
||||
* 响应头
|
||||
*/
|
||||
headers: Headers;
|
||||
|
||||
/**
|
||||
* Axios 请求配置
|
||||
*/
|
||||
config: AxiosRequestConfig;
|
||||
|
||||
/**
|
||||
* 开发者服务器返回的 cookies,格式为字符串数组
|
||||
*/
|
||||
cookies?: string[];
|
||||
|
||||
/**
|
||||
* 网络请求过程中一些关键时间点的耗时信息
|
||||
*/
|
||||
profile?: AnyObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截器成功的回调函数
|
||||
*/
|
||||
export declare interface InterceptorResolved<T = any> {
|
||||
(value: T): Promise<T> | T;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截器失败的回调函数
|
||||
*/
|
||||
export declare interface InterceptorRejected {
|
||||
(error: any): any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截器
|
||||
*/
|
||||
export declare interface Interceptor<T = any> {
|
||||
/**
|
||||
* 拦截器成功的回调函数
|
||||
*/
|
||||
resolved: InterceptorResolved<T>;
|
||||
|
||||
/**
|
||||
* 拦截器失败的回调函数
|
||||
*/
|
||||
rejected?: InterceptorRejected;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截器执行器
|
||||
*/
|
||||
export declare interface InterceptorExecutor<T = any> {
|
||||
(interceptor: Interceptor<T>): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截器管理器
|
||||
*/
|
||||
export declare interface InterceptorManager<T = any> {
|
||||
[x: string]: any;
|
||||
/**
|
||||
* 添加拦截器
|
||||
*
|
||||
* @param resolved 成功的回调函数
|
||||
* @param rejected 失败的回调函数
|
||||
*/
|
||||
use(resolved: InterceptorResolved<T>, rejected?: InterceptorRejected): number;
|
||||
|
||||
/**
|
||||
* 删除拦截器
|
||||
*
|
||||
* @param id 拦截器 id
|
||||
*/
|
||||
eject(id: number): void;
|
||||
|
||||
/**
|
||||
* 遍历所有拦截器
|
||||
*
|
||||
* @param executor 拦截器执行器
|
||||
* @param reverse 是否倒序遍历
|
||||
*/
|
||||
forEach(executor: InterceptorExecutor<T>, reverse?: 'reverse'): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Axios 拦截器
|
||||
*/
|
||||
export declare interface Interceptors {
|
||||
/**
|
||||
* request 请求拦截器
|
||||
*/
|
||||
request: InterceptorManager<AxiosRequestConfig>;
|
||||
|
||||
/**
|
||||
* response 响应拦截器
|
||||
*/
|
||||
response: InterceptorManager<AxiosResponse>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Axios 实例
|
||||
*/
|
||||
export declare interface Axios {
|
||||
/**
|
||||
* 默认配置
|
||||
*/
|
||||
defaults: AxiosRequestConfig;
|
||||
|
||||
/**
|
||||
* Axios 拦截器
|
||||
*/
|
||||
interceptors: Interceptors;
|
||||
|
||||
/**
|
||||
* 根据配置中的 url 和 params 生成一个 URI
|
||||
*
|
||||
* @param config 请求配置
|
||||
*/
|
||||
getUri(config: AxiosRequestConfig): string;
|
||||
|
||||
/**
|
||||
* 发送 HTTP 请求
|
||||
*
|
||||
* @param config 请求配置
|
||||
*/
|
||||
request<T extends Data>(
|
||||
config: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<T>>;
|
||||
|
||||
/**
|
||||
* 发送 HTTP 请求 OPTIONS
|
||||
*
|
||||
* @param url 请求地址
|
||||
* @param config 额外配置
|
||||
*/
|
||||
options<T extends Data>(
|
||||
url: string,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<T>>;
|
||||
|
||||
/**
|
||||
* 发送 HTTP 请求 GET
|
||||
*
|
||||
* @param url 请求地址
|
||||
* @param params 请求参数
|
||||
* @param config 额外配置
|
||||
*/
|
||||
get<T extends Data>(
|
||||
url: string,
|
||||
params?: Params,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<T>>;
|
||||
|
||||
/**
|
||||
* 发送 HTTP 请求 HEAD
|
||||
*
|
||||
* @param url 请求地址
|
||||
* @param params 请求参数
|
||||
* @param config 额外配置
|
||||
*/
|
||||
head<T extends Data>(
|
||||
url: string,
|
||||
params?: Params,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<T>>;
|
||||
|
||||
/**
|
||||
* 发送 HTTP 请求 POST
|
||||
*
|
||||
* @param url 请求地址
|
||||
* @param data 请求数据
|
||||
* @param config 额外配置
|
||||
*/
|
||||
post<T extends Data>(
|
||||
url: string,
|
||||
data?: Data,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<T>>;
|
||||
|
||||
/**
|
||||
* 发送 HTTP 请求 PUT
|
||||
*
|
||||
* @param url 请求地址
|
||||
* @param data 请求数据
|
||||
* @param config 额外配置
|
||||
*/
|
||||
put<T extends Data>(
|
||||
url: string,
|
||||
data?: Data,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<T>>;
|
||||
|
||||
/**
|
||||
* 发送 HTTP 请求 DELETE
|
||||
*
|
||||
* @param url 请求地址
|
||||
* @param params 请求参数
|
||||
* @param config 额外配置
|
||||
*/
|
||||
delete<T extends Data>(
|
||||
url: string,
|
||||
params?: Params,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<T>>;
|
||||
|
||||
/**
|
||||
* 发送 HTTP 请求 TRACE
|
||||
*
|
||||
* @param url 请求地址
|
||||
* @param config 额外配置
|
||||
*/
|
||||
trace<T extends Data>(
|
||||
url: string,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<T>>;
|
||||
|
||||
/**
|
||||
* 发送 HTTP 请求 CONNECT
|
||||
*
|
||||
* @param url 请求地址
|
||||
* @param config 额外配置
|
||||
*/
|
||||
connect<T extends Data>(
|
||||
url: string,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<T>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Axios 类接口
|
||||
*/
|
||||
export declare interface AxiosConstructor {
|
||||
new (config?: AxiosRequestConfig): Axios;
|
||||
}
|
||||
|
||||
/**
|
||||
* AxiosError 类继承自 Error
|
||||
*/
|
||||
export declare interface AxiosError extends Error {
|
||||
/**
|
||||
* 是 Axios 错误
|
||||
*/
|
||||
isAxiosError: boolean;
|
||||
|
||||
/**
|
||||
* 请求配置
|
||||
*/
|
||||
config: AxiosRequestConfig;
|
||||
|
||||
/**
|
||||
* 通用请求配置
|
||||
*/
|
||||
request: RequestConfig;
|
||||
|
||||
/**
|
||||
* Axios 响应体
|
||||
*/
|
||||
response?: AxiosResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消请求
|
||||
*/
|
||||
export declare interface Cancel {
|
||||
/**
|
||||
* 取消信息
|
||||
*/
|
||||
message?: string;
|
||||
|
||||
/**
|
||||
* 序列化
|
||||
*/
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消请求类接口
|
||||
*/
|
||||
export declare interface CancelConstructor {
|
||||
new (message?: string): Cancel;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消操作
|
||||
*/
|
||||
export declare interface CancelAction {
|
||||
(message?: string): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消操作执行器
|
||||
*/
|
||||
export declare interface CancelExecutor {
|
||||
(cancel: CancelAction): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消令牌
|
||||
*/
|
||||
export declare interface CancelToken {
|
||||
/**
|
||||
* 取消时被触发
|
||||
*/
|
||||
listener: Promise<Cancel>;
|
||||
|
||||
/**
|
||||
* 如果已经取消, 则抛出取消对象
|
||||
*/
|
||||
throwIfRequested(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消令牌 source
|
||||
*/
|
||||
export declare interface CancelTokenSource {
|
||||
/**
|
||||
* 取消令牌
|
||||
*/
|
||||
token: CancelToken;
|
||||
|
||||
/**
|
||||
* 取消操作
|
||||
*/
|
||||
cancel: CancelAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消令牌类接口
|
||||
*/
|
||||
export declare interface CancelTokenConstructor {
|
||||
new (executor: CancelExecutor): CancelToken;
|
||||
|
||||
/**
|
||||
* 返回一个 CancelTokenSource
|
||||
*
|
||||
* CancelTokenSource.token 是一个 CancelToken 对象
|
||||
*
|
||||
* CancelTokenSource.cancel 是一个 CancelAction 函数
|
||||
*
|
||||
* 调用 CancelTokenSource.cancel('这里可以填写您的错误信息')
|
||||
*
|
||||
* 取消请求 CancelTokenSource.token
|
||||
*/
|
||||
source(): CancelTokenSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Axios 实例基础拓展
|
||||
*
|
||||
* * 支持两种函数调用方式
|
||||
*/
|
||||
export declare interface AxiosBaseInstance extends Axios {
|
||||
/**
|
||||
* 发送 HTTP 请求
|
||||
*
|
||||
* 调用方式一
|
||||
*
|
||||
* @param config 请求配置
|
||||
*/
|
||||
<T extends Data>(config: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
||||
|
||||
/**
|
||||
* 发送 HTTP 请求
|
||||
*
|
||||
* 调用方式二
|
||||
*
|
||||
* @param url 请求地址
|
||||
* @param config 额外配置
|
||||
*/
|
||||
<T extends Data>(url: string, config?: AxiosRequestConfig): Promise<
|
||||
AxiosResponse<T>
|
||||
>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Axios 实例拓展
|
||||
*
|
||||
* * 支持两种函数调用方式
|
||||
*
|
||||
* * 同时拓展了一些静态属性和方法
|
||||
*/
|
||||
export declare interface AxiosInstance extends AxiosBaseInstance {
|
||||
/**
|
||||
* 创建 Axios 实例基础拓展
|
||||
*
|
||||
* @param defaults 自定义默认配置
|
||||
*/
|
||||
create(defaults?: AxiosRequestConfig): AxiosBaseInstance;
|
||||
|
||||
/**
|
||||
* Axios 类
|
||||
*/
|
||||
Axios: AxiosConstructor;
|
||||
|
||||
/**
|
||||
* 取消令牌 类
|
||||
*/
|
||||
CancelToken: CancelTokenConstructor;
|
||||
|
||||
/**
|
||||
* 检查错误是否来自取消请求
|
||||
*
|
||||
* @param value 判断的值
|
||||
*/
|
||||
isCancel: (value: any) => boolean;
|
||||
}
|
||||
|
||||
export interface ObjectTree<T = unknown> {
|
||||
[key: string]: T | ObjectTree<T>;
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
import { AxiosPlatform } from './core/adapter';
|
||||
import { AxiosRequestParams } from './core/Axios';
|
||||
|
||||
const _toString = Object.prototype.toString;
|
||||
|
||||
export function isDate(date: any): date is Date {
|
||||
return _toString.call(date) === '[object Date]';
|
||||
}
|
||||
|
||||
export function isPlainObject<T = never>(
|
||||
value: any,
|
||||
): value is [T] extends never[] ? AnyObject : T {
|
||||
return _toString.call(value) === '[object Object]';
|
||||
}
|
||||
|
||||
export function isUndefined(value: any): value is undefined {
|
||||
return typeof value === 'undefined';
|
||||
}
|
||||
|
||||
export function isString(value: any): value is string {
|
||||
return typeof value === 'string';
|
||||
}
|
||||
|
||||
export function isNull(value: any): value is null {
|
||||
return value === null;
|
||||
}
|
||||
|
||||
export function isFunction<T extends Function = Function>(
|
||||
value: any,
|
||||
): value is T {
|
||||
return typeof value === 'function';
|
||||
}
|
||||
|
||||
export function isArray<T = any>(value: any): value is T[] {
|
||||
return Array.isArray(value);
|
||||
}
|
||||
|
||||
export function isEmptyArray<T = any>(value: any): value is [] {
|
||||
return isArray<T>(value) && value.length === 0;
|
||||
}
|
||||
|
||||
export function isPlatform(value: any): value is AxiosPlatform {
|
||||
return (
|
||||
isPlainObject(value) &&
|
||||
isFunction(value.request) &&
|
||||
isFunction(value.upload) &&
|
||||
isFunction(value.download)
|
||||
);
|
||||
}
|
||||
|
||||
export function deepMerge<T = any>(...objs: T[]): T {
|
||||
const result: AnyObject = {};
|
||||
|
||||
objs.forEach((obj: AnyObject) =>
|
||||
Object.keys(obj).forEach((key) => {
|
||||
const val = obj[key];
|
||||
const resultVal = result[key];
|
||||
|
||||
if (isPlainObject(resultVal) && isPlainObject(val)) {
|
||||
result[key] = deepMerge(resultVal, val);
|
||||
} else if (isPlainObject(val)) {
|
||||
result[key] = deepMerge(val);
|
||||
} else {
|
||||
result[key] = val;
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
return result as T;
|
||||
}
|
||||
|
||||
export function pick<T extends AnyObject, K extends keyof T>(
|
||||
obj: T,
|
||||
...keys: K[]
|
||||
): Pick<T, K> {
|
||||
const _pick: Partial<T> = {};
|
||||
|
||||
keys.forEach((key: K) => (_pick[key] = obj[key]));
|
||||
|
||||
return _pick as Pick<T, K>;
|
||||
}
|
||||
|
||||
export function omit<T extends AnyObject, K extends keyof T>(
|
||||
obj: T,
|
||||
...keys: K[]
|
||||
): Omit<T, K> {
|
||||
const _omit = Object.assign({}, obj);
|
||||
|
||||
keys.forEach((key: K) => delete _omit[key]);
|
||||
|
||||
return _omit;
|
||||
}
|
||||
|
||||
export function revisePlatformApiNames(platform: AnyObject): AxiosPlatform {
|
||||
return {
|
||||
request: platform.request ?? platform.httpRequest,
|
||||
upload: platform.upload ?? platform.uploadFile,
|
||||
download: platform.download ?? platform.downloadFile,
|
||||
};
|
||||
}
|
||||
|
||||
export function assert(condition: boolean, msg: string) {
|
||||
if (!condition) {
|
||||
throwError(msg);
|
||||
}
|
||||
}
|
||||
|
||||
export function throwError(msg: string): void {
|
||||
throw new Error(`[axios-miniprogram]:${msg}`);
|
||||
}
|
||||
|
||||
function encode(str: string): string {
|
||||
return encodeURIComponent(str)
|
||||
.replace(/%40/gi, '@')
|
||||
.replace(/%3A/gi, ':')
|
||||
.replace(/%24/g, '$')
|
||||
.replace(/%2C/gi, ',')
|
||||
.replace(/%20/g, '+')
|
||||
.replace(/%5B/gi, '[')
|
||||
.replace(/%5D/gi, ']');
|
||||
}
|
||||
|
||||
function generateURL(url: string, serializedParams: string): string {
|
||||
const hashIndex = url.indexOf('#');
|
||||
|
||||
if (hashIndex !== -1) {
|
||||
url = url.slice(0, hashIndex);
|
||||
}
|
||||
|
||||
if (serializedParams === '') {
|
||||
return url;
|
||||
}
|
||||
|
||||
const prefix = url.indexOf('?') === -1 ? '?' : '&';
|
||||
|
||||
serializedParams = `${prefix}${serializedParams}`;
|
||||
|
||||
return `${url}${serializedParams}`;
|
||||
}
|
||||
|
||||
function paramsSerialization(params?: AxiosRequestParams): string {
|
||||
if (!isPlainObject(params)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const parts: string[] = [];
|
||||
|
||||
Object.keys(params).forEach((key): void => {
|
||||
const value = params[key];
|
||||
|
||||
if (isNull(value) || isUndefined(value) || value !== value) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
key += '[]';
|
||||
}
|
||||
|
||||
const values = [].concat(value);
|
||||
|
||||
values.forEach((val: any): void => {
|
||||
if (isPlainObject(val)) {
|
||||
val = JSON.stringify(val);
|
||||
} else if (isDate(val)) {
|
||||
val = val.toISOString();
|
||||
}
|
||||
|
||||
parts.push(`${encode(key)}=${encode(val)}`);
|
||||
});
|
||||
});
|
||||
|
||||
return parts.join('&');
|
||||
}
|
||||
|
||||
export function buildURL(
|
||||
url = '',
|
||||
params?: AxiosRequestParams,
|
||||
paramsSerializer = paramsSerialization,
|
||||
): string {
|
||||
if (!isPlainObject(params)) {
|
||||
return url;
|
||||
}
|
||||
|
||||
return generateURL(url, paramsSerializer(params));
|
||||
}
|
||||
|
||||
const combineREG = /\/{2,}/g;
|
||||
export function combineURL(baseURL = '', url: string): string {
|
||||
const separator = '/';
|
||||
|
||||
return `${baseURL}${separator}${url}`.replace(combineREG, separator);
|
||||
}
|
||||
|
||||
const dynamicREG = /\/?(:([a-zA-Z_$][\w-$]*))\/??/g;
|
||||
export function dynamicURL(url: string, params?: AxiosRequestParams): string {
|
||||
if (!isPlainObject(params)) {
|
||||
return url;
|
||||
}
|
||||
|
||||
return url.replace(dynamicREG, (key1, key2, key3) =>
|
||||
key1.replace(key2, params[key3]),
|
||||
);
|
||||
}
|
||||
|
||||
const absoluteREG = /^([a-z][a-z\d+\-.]*:)?\/\//i;
|
||||
export function isAbsoluteURL(url: string): boolean {
|
||||
return absoluteREG.test(url);
|
||||
}
|
|
@ -2,11 +2,13 @@
|
|||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"outDir": "dist",
|
||||
"sourceMap": true,
|
||||
"target": "esnext",
|
||||
"target": "ES5",
|
||||
"module": "esnext",
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"lib": ["esnext"]
|
||||
"declaration": true,
|
||||
"declarationDir": "dist/@types/axios-miniprogram",
|
||||
},
|
||||
"include": ["src", "__tests__"]
|
||||
"include": ["src/**/*", "global.d.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue