axios学习历程(遇到问题持续更新)

  1. axios的作用
  2. axios配置文件
  3. axios在使用中的一些坑

作用

axios其实就是vue-resourece的一个更优的基于Promise的解决方案,加上vue-resourece早已停止更新,fetch在配置中又十分的繁琐,这无疑让axios成为我的首选。

配置文件的说明

官方文档其实已经说明的很清楚了,在这里记录一下,便于断网的时候查询。

{
  // `url` 是用于请求的服务器 URL
  url: '/user',

  // `method` 是创建请求时使用的方法
  method: 'get', // 默认是 get

  // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
  // 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
  baseURL: 'https://some-domain.com/api/',

  // `transformRequest` 允许在向服务器发送前,修改请求数据
  // 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
  // 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
  transformRequest: [function (data) {
    // 对 data 进行任意转换处理

    return data;
  }],

  // `transformResponse` 在传递给 then/catch 前,允许修改响应数据
  transformResponse: [function (data) {
    // 对 data 进行任意转换处理

    return data;
  }],

  // `headers` 是即将被发送的自定义请求头
  headers: {'X-Requested-With': 'XMLHttpRequest'},

  // `params` 是即将与请求一起发送的 URL 参数
  // 必须是一个无格式对象(plain object)或 URLSearchParams 对象
  params: {
    ID: 12345
  },

  // `paramsSerializer` 是一个负责 `params` 序列化的函数
  // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
  paramsSerializer: function(params) {
    return Qs.stringify(params, {arrayFormat: 'brackets'})
  },

  // `data` 是作为请求主体被发送的数据
  // 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
  // 在没有设置 `transformRequest` 时,必须是以下类型之一:
  // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  // - 浏览器专属:FormData, File, Blob
  // - Node 专属: Stream
  data: {
    firstName: 'Fred'
  },

  // `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
  // 如果请求话费了超过 `timeout` 的时间,请求将被中断
  timeout: 1000,

  // `withCredentials` 表示跨域请求时是否需要使用凭证
  withCredentials: false, // 默认的

  // `adapter` 允许自定义处理请求,以使测试更轻松
  // 返回一个 promise 并应用一个有效的响应 (查阅 [response docs](#response-api)).
  adapter: function (config) {
    /* ... */
  },

  // `auth` 表示应该使用 HTTP 基础验证,并提供凭据
  // 这将设置一个 `Authorization` 头,覆写掉现有的任意使用 `headers` 设置的自定义 `Authorization`头
  auth: {
    username: 'janedoe',
    password: 's00pers3cret'
  },

  // `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
  responseType: 'json', // 默认的

  // `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称
  xsrfCookieName: 'XSRF-TOKEN', // default

  // `xsrfHeaderName` 是承载 xsrf token 的值的 HTTP 头的名称
  xsrfHeaderName: 'X-XSRF-TOKEN', // 默认的

  // `onUploadProgress` 允许为上传处理进度事件
  onUploadProgress: function (progressEvent) {
    // 对原生进度事件的处理
  },

  // `onDownloadProgress` 允许为下载处理进度事件
  onDownloadProgress: function (progressEvent) {
    // 对原生进度事件的处理
  },

  // `maxContentLength` 定义允许的响应内容的最大尺寸
  maxContentLength: 2000,

  // `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject  promise 。如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejecte
  validateStatus: function (status) {
    return status >= 200 && status < 300; // 默认的
  },

  // `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目
  // 如果设置为0,将不会 follow 任何重定向
  maxRedirects: 5, // 默认的

  // `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理。允许像这样配置选项:
  // `keepAlive` 默认没有启用
  httpAgent: new http.Agent({ keepAlive: true }),
  httpsAgent: new https.Agent({ keepAlive: true }),

  // 'proxy' 定义代理服务器的主机名称和端口
  // `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据
  // 这将会设置一个 `Proxy-Authorization` 头,覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头。
  proxy: {
    host: '127.0.0.1',
    port: 9000,
    auth: : {
      username: 'mikeymike',
      password: 'rapunz3l'
    }
  },

  // `cancelToken` 指定用于取消请求的 cancel token
  // (查看后面的 Cancellation 这节了解更多)
  cancelToken: new CancelToken(function (cancel) {
  })
}
// 响应结构
// 某个请求的响应包含以下信息

{
  // `data` 由服务器提供的响应
  data: {},

  // `status` 来自服务器响应的 HTTP 状态码
  status: 200,

  // `statusText` 来自服务器响应的 HTTP 状态信息
  statusText: 'OK',

  // `headers` 服务器响应的头
  headers: {},

  // `config` 是为请求提供的配置信息
  config: {}
}

其实这里的话是要 axios(config) 这样里面去的想一想这么多的配置文件要一股脑都塞进去,确实看起来是非常的不雅而且整个主代码会变得乱七八糟,没错,刚开始学习的我真的这样做了,后期几乎是完全没法维护的,后来我通过学习花裤衩大大的代码,才知道,这些东西是可以封装起来的,大概分出来两个文件。

首先是axios的配置文件(需要自己创建哦我个人是命名为request.js并且丢在src的utils文件夹中自己建的)

import axios from 'axios'
// axios配置信息
axios.defaults.withCredentials = true
const service = axios.create({
  baseURL: process.env.BASE_API, // api 的 前缀url
  timeout: 5000, // 请求超时
})
// 数据发送前的拦截器
service.interceptors.request.use(
  config => {
    return config
  },
  error => {
    Promise.reject(error)
  }
)
// 数据接受时的拦截器
service.interceptors.response.use((response) => {
  return response
}, (err) => {
  switch (err.response.status) {
    case 500:
      
      break;
    case 429:
      
      break;
    default:
      
  }

})

export default service

  1. 首先是这个配置文件,在axios.create这个方法中,有baseURL和timeout这两个配置,前者指向的是webpack的开发环境和生产环境,这个如果有自己配置的话,就在里面加一个baseURL即可,如果还不清楚的话,建议通过console来查看具体位置;再下面就是有两个拦截器,一个是数据发送前,一个是数据接受时,这两个拦截器用处很大,我这么配置之后,基本一目了然,在下面的res拦截器中,可以捕获到http错误码,可以通过判断和后端的错误码来给予用户最人性化的提示。
  2. 而在数据发送前的这个拦截器则可以统一配置 header等这一系列的东西从而避免在主代码中去重新设置这些东西,比如使用qs去转换需要发送的数据对吧,很方便的。

请求地址配置文件(同样是需要自己创建我个人是新建了一个目录api,然后把它放入新加的js文件中)

// 在此处导入之前配置的service
import request from 'request'
export default {
    // 内容为请求的函数,例如:
    post(data) {
    return request({
      url: "",
      method: "post",
      data
    })
  },
    get(params) {
    return request({
      url: "",
      method: "get",
      params
    })
  },
}

这里的请求配置文件就很明了了,导入之后使用 export default将其中的函数全部暴露出去方便调用,而函数内则是这样的一个结构,在函数内部配置一个 url,method,data,为什么要将这些配置分离出来配置而不是在之前的配置文件中使用,因为服务端提供的接口方式多是多样,可以是get,post,put,dele其中的任意一个,而url则是前面相同部分的服务器地址后面的接口地址那部分,听起来是不是有点绕?举个栗子:现在有两个接口,https://skyserver.com/get_list 和 https://skyserver.com/get_list 那么我就可以设baseURL为 https://skyserver.com,而这里的url则是 /get_list 或者是 /get_list ,明白了吗?每一个接口我们只需要更改后面的接口名和请求方式就好了。

如何去使用?

emm,其实使用方法有很多,我个人推荐是去main.js文件中去引入,例如我引入之后的名字是api那么我就可以使用这行代码Vue.prototype.$api = api意思为将这个挂载到vue的原型中去,这样的好处就是我们可以直接使用this.$api.get()的方式进行调用,由于axios本身就是一个基于Promise的项目,其实就可以直接使用async and await的形式来进行调用,借助webpack的一部分功能让自己的代码本体变得不再那么冗余。

踩过的坑

  1. axios本身不会发送cookie,需要你自己加上axios.defaults.withCredentials = true这句代码才会发送cookie,但是会存在跨域问题,在这里由于我只使用了nodejs作为后端所以只举例nodejs如何解决这个跨域问题的:

首先我使用的是的是express框架,不过影响不大,毕竟koa和其他的都是差不多的原理。话不多说先上代码:

// 我们可以直接获取访问服务器的来源直接赋值过去,虽然方便,但是要知道本身这个是防御XSS攻击,这么设置之后的风险阅读者应该要须知。
let origin = req.header.origin
//访问控制允许来源,有人会问为什么这里不是一个'*'呢,因为在启用了cookie之后,是不允许使用通配符的,所以在当需要发送cookie的场景中
res.header('Access-Control-Allow-Origin', origin);
//访问控制允许报头 X-Requested-With: xhr请求
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept,X-Token");
//访问控制允许方法
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
// 它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。
res.header("Access-Control-Allow-Credentials",true);
//自定义头信息,表示服务端用nodejs,其实你也可以发送其他的2333虽然意义不明
res.header('X-Powered-By', 'nodejs');
// 定义发送的数据格式
res.header('Content-Type', 'application/json;charset=utf-8');

这里出现的弊端,想必一眼就看出来了对吗?这里允许了所有来访者的url,但是事实上我们并不能这样允许,因为这样是有安全问题的!so,做个判断不就好啦:

// 这里规定一个白名单,允许哪些域名访问,是一个数组
let whitList = ['','']
// 这里则使用的是es6的语法,检查该变量是否存在于数组中
// 和es5中的 `indexOf()` 有异曲同工之妙,但是它返回的是一个布尔值,除了不能够定位元素的位置,但是用在此处很棒不是么~
if(whitList.includes(origin)){
    // 这里是上面的那段代码
}

  1. axios是基于es6语法的,你可能会遇到 Promise is not function 的问题,通常出现在老旧浏览器上,可以通过bable来进行转换。下图是其浏览器的支持。

Chrome
Firefox
Safari
Opera
Edge
IE
Latest ✔ Latest ✔ Latest ✔ Latest ✔ Latest ✔ 11 ✔
  1. 它拦截接收报错的信息是在 err.response 中,而不是直接的err就可以获取到,这一点是很坑的,一直以来我都以为是在err中,导致始终无法捕捉到http状态值以及报错信息,其实官方文档也有说明,如果我不是那么的星际也不会犯这种低级错误

你可能感兴趣的:(axios学习历程(遇到问题持续更新))