快速了解axios常用功能,适用于对axios有一定使用经验的人。

常用请求方法的参数

axios.get(url, config);

get方法支持两个参数,第一个是url,第二个是{}键值对配置对象。

axios.post(url, data, config);

post方法支持三个参数:请求地址,上传的数据{},{}键值对配置对象。

当然还有一些其他请求类型,可以查看官方文档,这两种常用。

除了.xxx方法使用协议,还可以直接传入配置对象的形式使用。

axios({
  method:'get',
  url:'xxxx',
})

这种方式比较适合封装使用。适用度广泛一些。

一些常用的config配置属性:

{
    //自定义头信息
    headers: {
        'X-Requested-With': 'XMLHttpRequest'
    },
    //配置在url地址上的参数
    params: {
        ID: 12345
    },
    //基础url地址,设置了baseUrl后,会将baseUrl和url属性进行拼接
    baseURL: 'https://some-domain.com/api/',
    //请求先对数据进行处理,
    transformRequest: [function(data, headers) {
        // 对 data 进行任意转换处理,只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法,一般封装时直接在拦截器统一做处理了
        return data;
    }],
    // `transformResponse` 在传递给 then/catch 前,允许修改响应数据
    transformResponse: [function(data) {
        // 对 data 进行任意转换处理
        return data;
    }],
    //请求最大限时,超过这个时间自动结束请求,状态为cancel
    timeout: 1000,
    //上传进度回调
    onUploadProgress: function(progressEvent) {
        // Do whatever you want with the native progress event
    },
    //下载进度回调
    onDownloadProgress: function(progressEvent) {
        // 对原生进度事件的处理
    },
    //取消请求方法
    cancelToken: new CancelToken(function(cancel) {})
}

这些都是常用的,或者以后会用到的,了解一下对以后处理问题有很大的帮助。

拦截器

拦截器分为:

  • 请求前拦截
  • 响应前拦截

请求前拦截

// 添加请求拦截器
axios.interceptors.request.use(function(config) {
    // 在发送请求之前做些什么
    return config;
}, function(error) {
    // 对请求错误做些什么
    return Promise.reject(error);
});

响应前拦截

// 添加响应拦截器
axios.interceptors.response.use(function(response) {
    // 对响应数据做点什么
    return response;
}, function(error) {
    // 对响应错误做点什么
    return Promise.reject(error);
});

说下拦截器一般的用途:

请求前拦截:主要负责统一处理添加头信息,格式转换,添加取消token

响应前拦截:由于axios会对响应的内容进行二次封装,所以后端实际返回的内容层级是:response.data,所以一般常用的做法就是在返回给前端处理前将这个data先提取出来,减少层级。

然后就是错误处理了,处理的错误有三种类型:请求出错(网络或代码出错)、后端返回报错、取消请求报错(取消后也是走的错误处理)

具体的做法百度很多优秀案例,看看就会明白,就不做废话。

axios封装的响应对象response了解

axios会将api返回的内容二次封装,有以下这些属性:

{
    // `data` 后端返回给你的内容
    data: {},

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

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

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

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

    //请求时创建的原生xhr对象
    request: {}
}

取消请求

取消请求我们需要在请求前的拦截器添加一个取消用的token,当然也可以写在单个的请求配置对象里面,但是就没啥必要了,这里就不多说,如果你想了解怎么在单个请求里面加入取消请求,可以看我这篇文章:《如何取消axios请求以及取消后错误处理的思路》

const CancelToken = axios.CancelToken;

//请求前拦截器
axios.interceptors.request.use(function(config) {
    //添加取消token
    const source = CancelToken.source();
    config.cancelToken = source.token;

    //取消请求
    source.cancel("取消请求");

    return config;
}, function(error) {
    // 对请求错误做些什么
    return Promise.reject(error);
});

如果你想在别的地方取消请求,自由度更大一些,那么就需要将每次拦截器触发是创建的source实例保存为全局的变量里面,你可以用window.xxx的方式,也可以利用vuex,这些都取决于你想怎么办。

source.cancel接受一个参数,这个参数就是取消时创建的取消错误对象的message属性。

最终这个请求会直接走promise的catch处理,所以我是建议哪怕你不需要对错误进行响应,也最好在axios请求后面接一个catch,并传入空的function,不然promise检测不到有人接收错误,就会直接全局抛出,我觉得你应该不想看到浏览器里面报这个错误。

这个错误是特殊的,并且axios提供了判断是否为取消请求的判断方法,前提你需要使用axios这个对象。

axios.isCancel(error);  //true

如果错误对象是取消请求返回的,那么就为true。

创建实例与并发处理

创建实例

axios使用的过程中,如果只能通过这一个实例来处理需求,那么深度定制的时候,就非常不便了,所以axios提供了创建新实例的方法,创建的新实例有自己的拦截器,用起来就非常方便了。

const instance = axios.create({
    baseURL: 'https://some-domain.com/api/',
    timeout: 1000,
    headers: {
        'X-Custom-Header': 'foobar'
    }
});

//请求前拦截器
instance.interceptors.request.use(function(config) {
    return config;
}, function(error) {
    return Promise.reject(error);
});

instance 为新的实例。

并发处理

axios实际也是用的promise的all方法,只是进行了一个封装,其实效果是一样的。

const xhr1 = axios.get("/xxx");
const xhr2 = axios.get("/xxx");

axios.all([xhr1, xhr2]).then(res => {
  console.log(res); //[response,response]
}).catch(err => {
  //错误处理
})

将两个请求的实例放入数组中,丢入all方法里面,all方法本身也是一个promise,他会等待所有请求成功完成触发then方法,并将返回的response结果数组(多个请求结果)返回。

这个结果数组的顺序会和你丢入all方法里面的请求方法数组顺序保持一致。

如果你想展开这个数组,axios也提供了一个spread方法,他会将数组展开,将响应对象作为参数一个个传给回调

const xhr1 = axios.get("/xxx");
const xhr2 = axios.get("/xxx");

axios.all([xhr1, xhr2]).then(axios.spread((res1,res2)=>{
  console.log(res1,res2); //response,response
})).catch(err => {
  //错误处理
})

东西一多,我感觉还是forEach省事。

跨域之CORS -- 后端配置

跨域的限制是因为浏览器的安全限制:同源策略,要求必须要是:

  1. 相同域名;
  2. 相同协议;
  3. 端口相同;
    的请求才允许访问使用。

但是也不一定所有的网页api接口都是遵循这个规则的,为此诞生了CORS方案。

CORS全称是“跨域资源共享”,它允许浏览器向跨源服务器发出xhr请求,从而克服了ajax只能同源使用的限制,cors是由后端发送一个响应头信息Access-Control-Allow-Orgin,以koa的ctx为例:

ctx.set("Access-Control-Allow-Orgin","*");

这将允许所有跨域的请求访问,如果需要限制域名,也可以设置具体的可允许跨域的域名。

ctx.set("Access-Control-Allow-Orgin","https://www.xxx.com");

多个值应该是用逗号隔开,这里是属于后端部分,就不细讲了,大概就是这么一回事。

跨域之JSONP -- 后端配合

jsonp应该是老生常谈的内容了,远古技术,其原理就是利用了script标签不受浏览器同源策略限制的特性,前端先预设好一个回调函数,这里假设名字为A,然后前端将请求地址作为script元素的src属性值,插入到body中,触发script元素加载src。

我们还需要在src地址上传入我们预设的回调函数A,因为script元素是一个get请求,其生成如下内容:

<script src="api地址?callback=A"></script>

这个时候,我们后端的api就会收到前端的get请求,我们获取到callback字段的参数A,其实这是一个string。

然后我们将需要给前端的内容作为回调函数的参数返回,大概返回如下内容。

ctx.body = "A({user:'xxxx',pass:'xxxx'})"

script接收到后端返回的内容,就会运行,因为这是一个js文件内容。

运行时,由于在运行前,我们已经申明的回调函数A,所以,运行成功。A会被触发,然后我们就可以在回调里书写我们需要进行的处理。

一般JSONP的封装可以如下书写,只是用于理解的例子:

function jsonp(url,callback) {
  //全局注册回调函数
  const reg = /callback=([^&]+)/;
  const callbackName = url.match(reg)[1];
  window[callbackName] = callback;
  //发起请求
  let script = document.createElement("script");
  document.body.append(script);
  //请求完成自我删除标签
  script.onload = function(){
    this.remove();
  };
}

删除标签,已运行的js代码会一直存在。

从某种角度来说,jsonp还是要依赖于后端,但是在后端CORS的方案下,jsonp已经用的很少了。

跨域之反代

反向代理指的是代理服务器接受来自客户端的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器得到的结果返回给连接的客户端。

反向代理一般用于:

  1. 内网安全
  2. 负载均很
  3. 跨域请求

因为服务器没有浏览器的同源策略,所以可以处理跨域的问题。

一般来说,反向代理建议使用nginx这种框架,在koa里面,我们想要进行一个反向代理,有一个可以很容易看出效果的办法,我们在koa框架里面通过axios请求一个跨域的api地址,你会发现在then回调中可以完美获取到数据,我们可以再将这个数据发送给前端,不就可以达到相同效果了,虽然比较麻烦一些,但是原理是一样的。

具体的做法就不多说了,我个人也很少用到这个,宝塔的反代还有可视化操作,比较简单。

axios展望

xhr的未来就是fetch请求,但是目前的fetch请求还不够强大,相信在未来的时间里,fetch会逐渐取代xhr,估计以后会有fxios这种基于fetch封装的,有名的请求库。

分类: JavaScript 标签: javascript跨域axios

评论

暂无评论数据

暂无评论数据

目录