shoutingwei / frontend-learning

0 stars 0 forks source link

axios的优点?有啥区别? #39

Open shoutingwei opened 6 years ago

shoutingwei commented 6 years ago

JQuery ajax

$.ajax({
   type: 'POST',
   url: url,
   data: data,
   dataType: dataType,
   success: function () {},
   error: function () {}
});

对原生XHR的封装,除此以外还增添了对JSONP的支持。 基于原生的XHR开发,XHR本身的架构不清晰,已经有了fetch的替代方案 JQuery整个项目太大,单纯使用ajax却要引入整个JQuery非常的不合理(采取个性化打包的方案又不能享受CDN服务)

Axios

axios({
    method: 'post',
    url: '/user/12345',
    data: {
        firstName: 'Fred',
        lastName: 'Flintstone'
    }
})
.then(function (response) {
    console.log(response);
})
.catch(function (error) {
    console.log(error);
});

Vue2.0之后,尤雨溪推荐大家用axios替换JQuery ajax,Axios本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范,支持: 从 node.js 创建 http 请求 支持 Promise API 客户端支持防止CSRF 提供了一些并发请求的接口 这个支持防止CSRF其实挺好玩的,是怎么做到的呢,就是让你的每个请求都带一个从cookie中拿到的key, 根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。

Axios既提供了并发的封装,也没有下文会提到的fetch的各种问题,而且体积也较小,当之无愧现在最应该选用的请求的方式。

Fetch 符合关注分离,没有将输入、输出和用事件来跟踪的状态混杂在一个对象里 更好更方便的写法,诸如:

try {
  let response = await fetch(url);
  let data = response.json();
  console.log(data);
} catch(e) {
  console.log("Oops, error", e);
}

更加底层,提供的API丰富(request, response) 脱离了XHR,是ES规范里新的实现方式 fetch是一个低层次的API,你可以把它考虑成原生的XHR,所以使用起来并不是那么舒服,需要进行封装 例如:

1)fetch只对网络请求报错,对400,500都当做成功的请求,需要封装去处理 2)fetch默认不会带cookie,需要添加配置项 3)fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了流量的浪费 4)fetch没有办法原生监测请求的进度,而XHR可以

fetch在前端的应用上有一项xhr怎么也比不上的能力:跨域的处理。 我们都知道因为同源策略的问题,浏览器的请求是可能随便跨域的——一定要有跨域头或者借助JSONP,但是,fetch中可以设置mode为"no-cors"(不跨域),如下所示:

fetch('/users.json', {
    method: 'post', 
    mode: 'no-cors',
    data: {}
}).then(function() { /* handle response */ });

这样之后我们会得到一个type为“opaque”的返回。需要指出的是,这个请求是真正抵达过后台的,所以我们可以使用这种方法来进行信息上报,在我们之前的image.src方法中多出了一种选择,另外,我们在network中可以看到这个请求后台设置跨域头之后的实际返回,有助于我们提前调试接口(当然,通过chrome插件我们也可以做的到)。

shoutingwei commented 6 years ago

fetch 跨域

  1. 如果服务器支持 CORS, 则在客户端设置相应的 Access-Control-Allow-Origin 即可得到数据。let ``` myHeaders = new Headers({ 'Access-Control-Allow-Origin': '*', 'Content-Type': 'text/plain' }); fetch(url, { method: 'GET', headers: myHeaders, mode: 'cors' }) .then((res) => { // TODO })


如果服务器返回的 response 头包含 “Access-Control-Allow-Origin:*”或者 *为与请求源相同的地址。即服务器支持浏览器跨域访问。若不包含需求修改服务器端,与浏览器端请求。

2. 如果服务器不支持 CORS,则不用使用 Fetch Api 了。`Fetch Api`  必须后台支持 `CORS`。

fetch的mode配置项有3个值,如下:

same-origin:该模式是不允许跨域的,它需要遵守同源策略,否则浏览器会返回一个error告知不能跨域;其对应的response type为basic。
cors: 该模式支持跨域请求,顾名思义它是以CORS的形式跨域;当然该模式也可以同域请求不需要后端额外的CORS支持;其对应的response 
type为cors。
no-cors: 该模式用于跨域请求但是服务器不带CORS响应头,也就是服务端不支持CORS;这也是fetch的特殊跨域请求方式;其对应的response 
type为opaque。

如果你设置了 `{mode: ' cors '}`(一般用于请求API),就会报错告诉你你请求的服务器不支持 `CORS`。大概会报下面的错误:
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
如果设置成 `{mode: ' no-cors '}` (一般用于请求图片等静态资源), 虽然不会报错,但是结果会 返回被标记了为  `opaque`  的数据,表明你没有权限访问。
![image](https://user-images.githubusercontent.com/38684977/43385526-87d2a730-9413-11e8-875d-d5624ed28687.png)

这种情况下可以使用 JSONP。