rewrite-axios v1.3.1
rewrite-axios
使用 TypeScript 实现 axios
第一次使用Markdown编写README,内容基本上都是Copy Axios官方文档来编写的
为了更好的说明,都是用中文来进行描述
下方有axios官方文档链接,小伙伴们可以去学习或看一下源代码实现
特此说明:此文档仅作为练习Markdown编写
Features
原生 XMLHttpRequest 结合 Promise 实现
使用 TypeScript 进行重写
符合官方 Axios 库的所有功能
Browser Support
Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | 11 ✔ |
axios官方文档链接: https://github.com/axios/axios
Installing
使用 npm
npm install --save rewrite-axios
Or
npm install -S rewrite-axios
Note: 由于使用 npm 进行安装速度会很慢,建议使用淘宝镜像 cnpm 或各大的源镜像进行安装
The introduction of axios
使用 ES6
语法的 import 导入
import axios from rewrite-axios
Example
发起一个普通的 GET
请求:
let request = axios({
method: 'GET', // 这里的方法不区分大小写
url: '/base/get', // 可以是相对路径或绝对路径
params: { // GET请求参数
foo: 123
}
})
当响应的时候可以这样:
request.then(res => {
// 请求返回值
}).catch(error => {
// 请求失败
})
Or
axios({
method: 'GET',
url: '/base/get',
params: {
foo: 123
}
}).then(res => {
// 请求返回值
}).catch(error => {
// 请求失败
})
使用 ES7
语法会更加简洁
async function test() {
try {
const data = axios({
method: 'GET',
url: '/base/get',
params: {
foo: 123
}
})
console.log(data) // 返回请求响应值
} catch(e) {
// 错误信息
}
}
Note:
async/await
并不是所有浏览器都支持,如果需要使用的话,请自行polyfill
进行向下兼容
请求中的 params
是一个对象,属性值支持多种格式:
instructions
URL: localhost:3000
const date = new Date()
params: {
foo: 123, // localhost:3000?foo=123
foo1: 'foo1', // localhost:3000?foo=foo1
foo2: '@:$, ', // localhost:3000?foo=@:$,+ (注意空格被转换为了+号)
foo3: [1, 2, 3], // localhost:3000?foo3[]=1&foo3[]=2&foo3[]=3
foo4: { // localhost:3000?foo4=foo=%7B%22bar%22:%22baz%22%7D
bar: 'baz'
},
foo5: date, // localhost:3000?date=2019-10-17T09:31:49.775Z
foo6: undefined, // localhost:3000
foo7: null // localhost:3000
}
Note: 当配置对象中的
url
有hash
值时,会被舍弃. 如:url: '/foo?bar=baz#hash'
,变为url: '/foo?bar=baz'
当 url 中有查询参数时,如果指定了 params 对象并且是符合上述除了 foo6 和 foo7 以外的任意一种,那么会追加到 url. 如:url: '/foo?bar=baz',params: { foo: 123 }
, url 变为'/foo?bar=baz&foo=123'
发起一个普通的 post
请求
axios({
method: 'POST',
url: '/base/post',
data: {
a: 1,
b: 2
}
}).then(res => {
console.log(res)
}).catch(error => {
console.log(error)
})
Note: 和
GET
请求一样,这里指定data
选项,需要向服务器发送的数据. 支持ArrayBuffer
、Blob
、Object
、URLSearchParams
等数据类型.
执行多个并发请求
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()]).then(axios.spread(function (acct, perms) {
// 只有当两个请求都发送成功后才可以拿到返回值
}))
Note: 参数数组中可调用可不调用
可以用普通对象作为参数传进 axios.all
方法
function p1() {
return 111
}
function p2() {
return Promise.resolve(2)
}
function p3() {
return Promise.resolve(3)
}
let obj = {
0: p1,
1: p2,
2: p3
}
axios.all(obj).then(axios.spread(function(res1, res2, res3) {
// 请求返回值
})).catch()
Note: 这里的对象键值应该用数字作为键值,否则可能会发生错误的意外. 对象的值可以是任意值,避免用undefined或null作为值. ( 如果是函数的话,请确保函数要return出一个值( 不支持嵌套函数 ) )
axios API
可以通过将相关配置传递给axios来发出请求
axios(config)
// 发起一个 POST 请求
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'hello',
lastName: 'world'
}
})
axios({
method: 'GET',
url: '/base/get?foo=bar',
params: {
bar: 'baz'
}
})
axios(url, config?)
axios('/user/12345')
Request method aliases
为了方便起见,为所有受支持的请求方法提供了别名.
- axios.request(config)
- axios.get(url, config)
- axios.delete(url, config)
- axios.head(url, config)
- axios.options(url, config)
- axios.post(url[, data, config])
- axios.put(url[, data, config])
- axios.patch(url[, data, config])
Note: 当使用别名方法 url 时,不需要在配置中指定方法和数据属性.
Concurrency
用于处理并发请求的辅助函数.
- axios.all(iterable)
- axios.spread(callback)
Note: iterable表示必须是可供 for...of 循环的数据 如string、array、带有Symbol.iterator接口对象的数据都是可以的. 当然实际用的最多的是数组类型
Creating an instance
可以使用自定义配置创建axios
的新实例
axios.create(config)
const instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {
'X-Custom-Header': 'foobar'
}
})
instance.get('/user?foo=bar')
const instance = axios.create()
instance.defaults.baseURL = 'https://some-domain.com/api/'
instance.defaults.timeout = 1000
instance.defaults.headers['X-Custom-Header'] = 'foobar'
Instance methods
下面列出了可用的实例方法。指定的配置将与实例配置合并.
- axios#request(config)
- axios#get(url, config)
- axios#delete(url, config)
- axios#head(url, config)
- axios#options(url, config)
- axios#post(url[, data, config])
- axios#put(url[, data, config])
- axios#patch(url[, data, config])
- axios#getUri(config)
Request Config
这些是用于发出请求的可用配置选项。只需要url
。如果没有指定方法,请求将默认为GET
.
{
// url是用于请求的服务器url
url: '/user',
// method是在发出请求时使用的请求方法
method: 'get', // default
// 以baseURL开头,后面跟着url(baseURL + url)
// 如果baseURL没有设置,将使用浏览器自动设置的baseURL
// 如:开发时的URL是http://localhost:3000(url选项指定的情况)
// 那么请求的地址为http://localhost:3000/user
// 如果url选项是一个完整的绝对地址,那么将使用这个地址
// 注意:跨域请求不需要设置baseURL,如果使用了像http-proxy-middleware这样的跨域代理插件,请在插件选项中设置baseURL
baseURL: 'https://some-domain.com/api/',
// 请求拦截器
// 允许在请求数据发送到服务器之前对其进行更改
// 只适用于请求方法"PUT"、"POST"、"PATCH"和"DELETE"
transformRequest: [function (data, headers) {
return data;
}],
// 响应拦截器
// 在响应前做些什么
transformResponse: [function (data) {
return data;
}],
// 设置请求头,红宝书建议使用自定义请求头
headers: {'X-Requested-With': 'XMLHttpRequest'},
// 与请求一起发送的URL参数
// 必须是一个plainObject或URLSearchParams对象
params: {
ID: 12345
},
// 负责序列化params
paramsSerializer: function (params) {
return Qs.stringify(params, {arrayFormat: 'brackets'})
},
// 作为请求体发送的数据
// 仅适用于请求方法"PUT"、"POST"和"PATCH"
data: {
firstName: 'Fred'
},
// 设置超时的时间(毫秒级)
// 超过指定的时间,请求将被终止
timeout: 1000, // default is `0` (no timeout)
// 指示是否跨站点访问控制请求
withCredentials: false, // default
// HTTP基本认证
// 用于验证用户
auth: {
username: 'janedoe',
password: 's00pers3cret'
},
// 服务器响应的数据类型
responseType: 'json', // default
// 用作xsrf token的cookie的名称
xsrfCookieName: 'XSRF-TOKEN', // default
// 携带xsrf令牌值的http头的名称
xsrfHeaderName: 'X-XSRF-TOKEN', // default
// 上传进度事件
onUploadProgress: function (progressEvent) {
},
// 下载进度事件
onDownloadProgress: function (progressEvent) {
},
// 自定义状态码范围
// 返回一个boolean类型
validateStatus: function (status) {
return status >= 200 && status < 300; // default
},
// 取消请求
cancelToken: new CancelToken(function (cancel) {
})
}
The response format
{
// 响应数据信息
data: {
a: 3
b: 4
},
// 响应状态码信息
status: 200,
// 响应文本信息
statusText: 'OK',
// 响应头信息
headers: {
connection: "keep-alive"
content-length: "13"
content-type: "application/json; charset=utf-8"
date: "Fri, 18 Oct 2019 05:40:46 GMT"
etag: "W/\"d-talgBZSHcQOay+ud5zDrtp+2VNk\""
x-powered-by: "Express"
},
// 请求配置信息
config: {
data: "{"a":1,"b":2}"
headers: {Accept: "application/json, text/plain, */*", Content-Type: "application/json;charset=utf-8"}
method: "post"
timeout: 0
transformRequest: [ƒ]
transformResponse: [ƒ]
url: "/base/post"
validateStatus: ƒ (status)
xsrfCookieName: "XSRF-TOKEN"
xsrfHeaderName: "X-XSRF-TOKEN"
},
// 响应的请求(XMLHttpRequest实例)
request: {
onabort: null
onerror: ƒ handleError()
onload: null
onloadend: null
onloadstart: null
onprogress: null
onreadystatechange: ƒ handleLoad()
ontimeout: ƒ handleTimeout()
readyState: 4
response: {a: 3, b: 4}
responseText: (...),
responseType: "json"
responseURL: "http://localhost:8080/base/post"
responseXML: (...)
status: 200
statusText: "OK"
timeout: 0
upload: XMLHttpRequestUpload {onloadstart: null, onprogress: null, onabort: null, onerror: null, onload: null, …}
withCredentials: false
}
}
使用then
时,将收到如下响应
axios.get('/user/12345')
.then(function (response) {
console.log(response.data);
console.log(response.status);
console.log(response.statusText);
console.log(response.headers);
console.log(response.config);
})
当使用catch
或将拒绝回调作为then
的第二个参数传递时,响应将通过error
对象可用,将处理错误部分逻辑
Config Defaults
可以指定将应用于每个请求的配置默认值.
Global axios defaults
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
Custom instance defaults
// 在创建实例时设置默认配置
const instance = axios.create({
baseURL: 'https://api.example.com'
});
// 创建实例后更改默认值
instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
Config order of precedence
Config将以优先顺序合并.
顺序是在src/defaults.js
文件中找到默认值,然后是实例的defaults
属性,最后是请求的config
参数.
后者将优先于前者
// 创建一个axios实例
// 此时,超时配置值为 0 (默认值)
const instance = axios.create();
// 覆盖超时默认值
// 现在超时为2500ms
instance.defaults.timeout = 2500;
// 再覆盖此请求的超时,超时时间设置为5000ms
// 结果是以最后配置的超时为准
instance.get('/longRequest', {
timeout: 5000
});
Interceptors
可以在请求或响应被处理之前做点额外的工作
// 添加一个请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 处理请求错误
return Promise.reject(error);
});
// 添加一个响应拦截器
axios.interceptors.response.use(function (response) {
// 位于2xx范围内的任何状态代码都会触发此函数
// 对响应数据做些什么
return response;
}, function (error) {
// 任何超出2xx范围的状态码都会触发此函数
// 处理响应错误
return Promise.reject(error);
});
如果您稍后需要删除拦截器,您可以这样做:
const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
您可以将拦截器添加到axios的自定义实例中( 推荐 )
const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
Handling Errors
axios.get('/user/12345')
.catch(function (error) {
if (error.response) {
// 发出请求后,服务器用状态码进行响应
// 这超出了2xx的范围
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// 提出了请求,但没有收到答复
// 超时或4xx错误
console.log(error.request);
} else {
// 在设置触发错误的请求时发生了一些事情
console.log('Error', error.message);
}
console.log(error.config);
});
使用validateStatus配置选项,您可以定义应该抛出错误的HTTP代码。
axios.get('/user/12345', {
validateStatus: function (status) {
// 仅当状态码大于或等于500时才拒绝
return status < 500;
}
})
Cancellation
您可以使用cancel token取消请求。
Note: axios cancel token API是可取消promise的提议
您可以在配置选项中指定CancelToken属性,这将创建一个cancel token!然后使用CancelToken内置的source方法为其赋值。像这样:
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token
}).catch(function (thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// handle error
}
});
axios.post('/user/12345', {
name: 'new name'
}, {
cancelToken: source.token
})
// 取消请求(消息参数是可选的)
source.cancel('Operation canceled by the user.');
您还可以通过将执行器函数传递给CancelToken构造函数来创建cancel token
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// 执行器函数接收一个cancel函数作为参数
cancel = c;
})
});
// 取消请求
cancel();
您可以使用相同的cancel令牌取消多个请求
Note: 通过在配置选项中指定
cancelToken
属性,当为cancelToken属性赋值为source.token
时,内部的promise
会resolve出去一个信息,然后在发送请求前确认是否有cancelToken
属性,有则取消,无则什么也不做! 通过简单的抛出一个错误就可达到取消请求目的。静态方法source
方法暴露出了两个方法:
- source: 是CancelToken类的实例
- cancel: 用来取消请求的方法
Using application/x-www-form-urlencoded format
请参见官网描述!