closertb.github.io icon indicating copy to clipboard operation
closertb.github.io copied to clipboard

紧跟时尚,Fetch实践那些事

Open closertb opened this issue 5 years ago • 0 comments

写于:2017-07-09

今天看到关于阿里前端面试的提问,看到有一个兄弟说,阿里应该都用fecth了,怎么还在考ajax的底层实现,虽然以前读ajax已死,fetch永生文章时有了解这个知识,但闲着也是闲着,还是探索一下,才知道他好在那。 老规矩,看官方正式一点的文章,我还是推荐MDN的,读完个人理解,对比ajax,fetch的优势就是:

  • 语义化强,调用如ajax第三方库一样简洁;
  • 支持promise;

干活

来看一个简单的调用:

fetch('http://localhost:8089/StockAnalyse/BlogServlet', fetchInitOption({flag:"getList"}))
  .then(function(response){
    if(response.ok){  //避免404与500这样的响应
            return response.json();
    } else {
        console.error('服务器繁忙,请稍后再试;\r\nCode:' + response.status)
    }
  }).then(function(data){
    that.item =data;//在promise中this指向已经变为指向window对象,所以提前用that保存了this;
    that = null;
  });             

如果你用过ajax第三方库,如jquery,vue-resource,axios这些,你会发现,fetch调用方法和这些库相似性非常之大,再看option的那些可设置属性:

 method: GET/POST...
 headers: 和其他header设置一样,主要设置Content-type和自定义header;
 body: 要传递的数据
 mode: cors / no-cors / same-origin,默认为 no-cors
 credentials: omit / same-origin / include
 cache: default / no-store / reload / no-cache / force-cache / only-if-cached
 redirect: follow / error / manual
 referrer: no-referrer / client / 
 referrerPolicy: no-referrer / no-referrer-when-downgrade / origin /  origin-when-cross-origin / unsafe-url
 integrity:

用fetch遇到的新鲜事

  1. 不管是404,还是500这些错误,请求仍然有response响应,所以才有response.ok状态值的判断;
  2. 当我们使用第三方ajax库发送post请求,数据数据为js对象且设置Content-type为application/x-www-form-urlencoded,服务器都能正常响应(数据读取为request.getPrameter);但Fetch这样设置就会导致服务器500错误,原因就在于Fetch它如AJAX一样,是一个底层的API,没有封装类似的数据转换,第三方库都自带,关于post请求常用的Content-type,所以为了不修改服务器端,我在配置post默认请求头时,对发送数据乃做了一定处理,不过仅适用于简单JS对象,目的就是将对象转化为键值对的方式,代码如下:
function fetchInitOption(json){
 let res=new Array();
 for(let item in json){
   res.push(item+'='+json[item])
 }
 return {
   method:'post',
   mode:'cors',
   headers: {
       'Content-Type': 'application/x-www-form-urlencoded'
   },
   body:res.join('&')            
 };                   
} 
  1. this指向变化(这个不算fetch的坑,这是编程应注意的问题),因为我用了vue,实例中的this默认指向当前vue实例,但是当调用fetch这个方法在promise的响应的匿名函数里,this指向了window对象,所以这里需要提前用一个变量that来保持实例this的引用;

  2. 请求前的拦截,就是在请求前想在header中加入自定义请求头,如TOKEN,不过好像解决思路一样,也可以在InitOption时手动设置;

虽路无尽头,但步伐坚定(早上一杯鸡汤,美好的周末即将开始)

closertb avatar Oct 03 '19 14:10 closertb