1.3.1 • Published 5 years ago

rewrite-axios v1.3.1

Weekly downloads
1
License
MIT
Repository
github
Last release
5 years ago

rewrite-axios

使用 TypeScript 实现 axios

第一次使用Markdown编写README,内容基本上都是Copy Axios官方文档来编写的

为了更好的说明,都是用中文来进行描述

下方有axios官方文档链接,小伙伴们可以去学习或看一下源代码实现

特此说明:此文档仅作为练习Markdown编写

Features

  • 原生 XMLHttpRequest 结合 Promise 实现

  • 使用 TypeScript 进行重写

  • 符合官方 Axios 库的所有功能

Browser Support

Chrome LogoFirefox LogoSafari LogoOpera LogoEdge LogoExplorer Logo
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: 当配置对象中的 urlhash值时,会被舍弃. 如: 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 选项,需要向服务器发送的数据. 支持 ArrayBufferBlobObjectURLSearchParams 等数据类型.

执行多个并发请求

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

为了方便起见,为所有受支持的请求方法提供了别名.

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

下面列出了可用的实例方法。指定的配置将与实例配置合并.

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

请参见官网描述!

链接地址: Using application/x-www-form-urlencoded format

1.3.1

5 years ago

1.2.8

5 years ago

1.2.6

5 years ago

1.2.4

5 years ago

1.2.2

5 years ago

1.2.1

5 years ago

1.1.8

5 years ago

1.1.4

5 years ago

1.0.1

5 years ago

0.1.8

5 years ago