Vue全家桶系列之Axios(二)

1.前言

上篇文章介绍了Axios的一些基本知识,这篇文章来说下Axios的一些进阶内容!

2.Axios实例

可以使用自定义配置新建一个 axios 实例,可以在这个实例上创建一些公共配置(默认值),方便其他地方调用!

let instance = this.$http.create({
  baseURL:
    "https://www.fastmock.site/mock/257d9fdebd0b1dd887acd6ec80db8ade/cena",
  validateStatus: function (status) {
    return status >= 200 && status < 300;
  },
  timeout: 1000
});

我们可以用指定的配置(和axios的配置内容一样)将与实例的配置合并,合并出你想要请求的配置,下面是可用的实例方法:

1. instance.delete(url[, config])
2. instance.head(url[, config])
3. instance.options(url[, config])
4. instance.get(url[, config])
5. instance.post(url[, data[, config]])
6. instance.put(url[, data[, config]])
7. instance.patch(url[, data[, config]])

接下来我们简单来模式下get和post的配置合并,它们区别只是url的相对路径不一样!

let instance = this.$http.create({
  baseURL:
    "https://www.fastmock.site/mock/257d9fdebd0b1dd887acd6ec80db8ade/cena",
  validateStatus: function (status) {
    return status >= 200 && status < 300;
  },
  timeout: 1000,
});

instance.post("/post/test").then(function (response) {
    console.log(response);
  }).catch(function (error) {
    console.log(error);
  });

instance.get("/get/test").then(function (response) {
    console.log(response);
  }).catch(function (error) {
    console.log(error);
  });

在这里插入图片描述
看上图可以看出请求的响应结构有下面几个属性:

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

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

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

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

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

// 在浏览器中 它是XMLHttpRequest的一个实例
// `response.request instanceof XMLHttpRequest`为true
request: {}

既然实例上面可以配置一些公共属性(默认值),那么全局可不可以也配置一些公共属性(默认值),答案是可以的(需要添加defaults属性),那么这里就有个配置的优先顺序了,请求的 config 参数>实例的默认属性>全局的默认属性,下面拿个timeout属性来测试下!

//全局的timeout为100
this.$http.defaults.timeout = 100;

//实例的timeout为1000
let instance = this.$http.create({
  baseURL:
    "https://www.fastmock.site/mock/257d9fdebd0b1dd887acd6ec80db8ade/cena",
  validateStatus: function (status) {
    return status >= 200 && status < 300;
  },
  timeout: 1000,
});

//请求参数的timeout为10000
instance.post("/post/test",
	{
      a: 1,
      b: 2,
    },
    {
      timeout: 10000,
    }
  ).then(function (response) {
    console.log(response);
  }).catch(function (error) {
    console.log(error);
  });

根据配置的优先顺序,应该最后timeout为请求的 config参数10000毫秒!
在这里插入图片描述

3.请求和响应拦截

拦截器分为全局的拦截器和实例拦截器,先来看下全局的拦截器!

//全局请求拦截
this.$http.interceptors.request.use((config) => {
     //为请求头添加token
     config.headers.common["Authorization"] = "Bearer token";
     return config;
   },(error) => {
     // 对请求错误做些什么
     return Promise.reject(error);
   }
);

//全局响应拦截
this.$http.interceptors.response.use((response) => {
    // 对响应数据做点什么
    return response;
  },(error) => {
    // 对响应错误做点什么
    return Promise.reject(error);
  }
);
  
 
this.$http.post("https://www.fastmock.site/mock/257d9fdebd0b1dd887acd6ec80db8ade/cena/post/test"
   ).then(function (response) {
     console.log(response);
   }).catch(function (error) {
     console.log(error);
});

 this.$http.get("https://www.fastmock.site/mock/257d9fdebd0b1dd887acd6ec80db8ade/cena/get/test"
   ).then((response) => {
     console.log(response);
   }).catch(function (error) {
     console.log(error);
});

也可以为自定义 axios 实例添加拦截器!

//创建实例
let instance = this.$http.create({
     baseURL:"https://www.fastmock.site/mock/257d9fdebd0b1dd887acd6ec80db8ade/cena",
     validateStatus: function (status) {
       return status >= 200 && status < 300;
     },
});

//实例请求拦截
instance.interceptors.request.use((config) => {
    //为请求头添加token
    config.headers.common["Authorization"] = "Bearer token";
    return config;
  },(error) => {
    // 对请求错误做些什么
    return Promise.reject(error);
  }
);


//实例响应拦截
instance.interceptors.response.use((response) => {
    // 对响应数据做点什么
    return response;
  },(error) => {
    // 对响应错误做点什么
    return Promise.reject(error);
  }
);

instance.post("/post/test").then(function (response) {
    console.log(response);
  }).catch(function (error) {
    console.log(error);
});

instance.get("/get/test").then((response) => {
    console.log(response);
  }).catch(function (error) {
    console.log(error);
});

如果你想移除拦截器,可以这样:

let myInterceptor = this.$http.interceptors.request.use(function () {.....});
//移除全局请求拦截
this.$http.interceptors.request.eject(myInterceptor);

let myInterceptorInstance = instance.interceptors.request.use(function () {.....});
//移除实例请求拦截
instance.interceptors.request.eject(myInterceptorInstance);

4.取消请求

有两种写法,先看下第一种写法!

let Http = this.$http,
   CancelToken = Http.CancelToken,
   that = this;
   
 Http.post(
     "https://www.fastmock.site/mock/257d9fdebd0b1dd887acd6ec80db8ade/cena/post/test",
     {},
     {
       cancelToken: new CancelToken((e) => {
         that.cancel = e;
       }),
     }
   )
   .then(function (response) {
     console.log(response);
   })
   .catch(function (error) {
     if (Http.isCancel(error)) {
     	//Request canceled 手动取消请求
       console.log("Request canceled", error.message);
     } else {
     ///.....
     
     }
});
this.cancel("手动取消请求");

再看下第二种写法:

let Http = this.$http,
  CancelToken = Http.CancelToken;
  this.source =CancelToken.source();
Http.post(
    "https://www.fastmock.site/mock/257d9fdebd0b1dd887acd6ec80db8ade/cena/post/test",
    {},
    {
      cancelToken: this.source.token
    }
  )
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    if (Http.isCancel(error)) {
      console.log("Request canceled", error.message);
    } else {
    ///
    }
 });
this.source.cancel("手动取消请求");

这里不多作解释了,其实就是原生xhr.abort的封装,有兴趣的朋友可以看下这篇文章axios之取消请求源码分析!

5.XSRF防御

CSRF英文全名(cross Site Request Forgery)跨站点请求伪造,攻击者盗用了你的身份,以你的名义向你的信任网站发送恶意请求,给你造成个人隐私泄露及财产安全。

1 . 下面用个例子来说明下它的原理!

你访问了登录一个银行A网站,然后A会保存你的个人信息并向浏览器返回一个cookie,这个cookie是有个过期时间的,在这个过期时间内,你可能又在逛什么别的网站,看到一个广告,你进了进去,那么恭喜你!你访问了一个恶意B网站,它用一些恶意代码要求你去访问银行A网站,而你的浏览器在收到这个恶意请求之后,在你不知情的情况下,带上保存在本地浏览器的cookie信息去访问银行A网站,银行A网站验证cookie通过误认为是用户自己本人操作,导致恶意B网站的代码被顺利执行(从你的账户转走了1000元)!

2 . Axios 如何防范?
上面文章说到Axios 通过相关配置来创建请求,说了些比较常用的,并没有提到有关CSRF 的配置,Axios 提供了 xsrfCookieName 和 xsrfHeaderName 两个属性来分别设置 CSRF 的 Cookie 名称和 HTTP 请求头的名称,它们的默认值如下所示:

// `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称
xsrfCookieName: 'XSRF-TOKEN', // default
// `xsrfHeaderName` 是用作http请求头的名称
xsrfHeaderName: 'X-XSRF-TOKEN', // default

其实两个csrf都是默认配置,就算不写也会在config配置中。
在这里插入图片描述
我们知道在不同的平台中,Axios 使用不同的适配器来发送 HTTP 请求,这里我们以浏览器平台为例,来看一下 Axios 如何防御 CSRF 攻击的。

//判断下是不是标准的浏览器
if (utils.isStandardBrowserEnv()) {
  var xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && config.xsrfCookieName ?
    cookies.read(config.xsrfCookieName) :
    undefined;
  if (xsrfValue) {
    requestHeaders[config.xsrfHeaderName] = xsrfValue;
  }
}

withCredentials表示跨域请求时是否要使用凭证(默认false),isURLSameOrigin(fullPath)是验证下发送请求的地址和当前浏览器地址是不是同源的(判断主机和协议是否相同),并看下config配置中有没有xsrfCookieName 属性。再来看下 cookies.read下面代码:

read: function read(name) {
  var match = document.cookie.match(new RegExp('(^|;\\s*)(' + name + ')=([^;]*)'));
  return (match ? decodeURIComponent(match[3]) : null);
}

去匹配到cookie里面'XSRF-TOKEN=(xxxxxxxxxxx'),用于从cookie中获取XSRF-TOKEN的值 ,([^;.]*) 是命名捕获,表示从匹配到的内容中 只获得 ()内的值。说白了就是获取等号后面的xxxx值,如果获取到了就requestHeaders["X-XSRF-TOKEN"]=xxxx。看完以上的代码,相信你已经知道了 Axios 内部是使用双重 Cookie 防御的方案来防御 CSRF 攻击。其实就是就是将 token 设置在 Cookie中,在提交请求时提交 Cookie,并通过请求头或请求体带上 Cookie 中已设置的 token,服务端接收到请求后,再进行对比校验。

6.总结

再来回顾下Axios有什么特性?我想你应该可以全部说出来了!

1. 因为返回的就是Promise,所以支持 Promise API。
2. 可以请求拦截和响应拦截。
3. 可以转换你所需要的请求数据和响应数据。
4. 可以手动取消请求。
5. 可以设置你需要返回的数据类型,默认是JSON,所以不设置也会自动转换 JSON 数据。
6. 客户端支持防御 XSRF(双重Cookie防御CSRF攻击)。

说了这里也说的差不多了,如果觉得写的可以,能帮助到你,可以点个关注!多谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值