微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

前端 fetch 通信

本文摘至: please call me HR

随着前端异步的发展,XHR 这种耦合方式的书写不利于前端异步的 Promise 回调. 而且,写起来也是很复杂. fetch API 本来是在 SW(ServiceWorkers) 中提出的,不过,后面觉得好用,就把他挂载到 window 对象下. 这样,在前端的正常通信中,我们也可以直接调用. 但,fetch 毕竟比较新,看一下他的兼容性.

在 PC 端上,就 FF,Opera 和 Chrome 比较 fashion. mobile 的话,基本上是不能用的. 当然,前端一直是个拥抱变化的职业,官方已经有一个现成的 polyfill 可以使用. 这样的话,就没必要过多担心.

每用到一个新的 feature,我们首先得知道他能不能用. Modernizr 这个库做的挺好的. 这里,我们简单的了解一下就 ok 了.

let isFetch = window.fetch?true:false;

fetch 基本格式

可以说,fetch 就是 ajax + Promise. 使用的方式和 jquery 提供的 $.ajax() 差不多.

fetch('./api/some.json')  
  .then(  
    function(response) {  
      if (response.status !== 200) {  
        console.log(`返回的响应码${response.status}`);  
        return;  
      }

      // 获得后台实际返回的内容
      response.json().then(function(data) {  
        console.log(data);  
      });  
    }  
  )  
  .catch(function(err) {  
    console.log('Fetch Error :-S',err);  
  });

上面的 demo 很好的参数了,fetch 的几个特点.

  • then()

  • catch()

  • json()

then 和 catch 是 promise 自带的两个方法,我这里就不多说了. 我们来看一下,json 是干嘛的.

因为返回回来的数据不仅仅包括后台的返回的 Text 内容,还有一些 Headers. 所以在,then 方法里面返回来的 res 实际上并不是我们在业务中想要的内容. 就和在 XHR 里返回数据是一个道理,我们最终要的是 responseText 这个数据. 而 json() 方法实际做的事情,就是调用 JSON.parse() 处理数据,并且返回一个新的 Promise. 看一下 polyfill 源码就应该了解.

this.json = function() {
    return this.text().then(JSON.parse)
}

fetch 传输格式

上面的 demo 是一个 get 方法的请求,当然,除了 get,还有其他的 HTTP Method,PUT,DELETE,POST,PATCH 等. 这里,我们就说一个 POST,其他方法的基本格式还是类似的.

fetch("http://www.example.org/submit.PHP",{
  method: "POST",headers: {
    "Content-Type": "application/x-www-form-urlencoded"
  },body: "this is a post Msg"
}).then(function(res) {
  if (res.ok) {
    // doSth
  } else if (res.status == 401) {
    // doSth
  }
});

看起来 fetch 和 $.ajax 并没有多大的区别...
but... fetch 里面的内容,真不少. 往底层看一看,fetch 实际上是 Request,Headers,Response 3个接口的整合. 不过,这3个只能在 SW 里面使用. 这里当做原理,参数一下即可.

Headers 操作

Headers 的操作无非就是 CRUD,这里我就不过多赘述,直接看代码吧:

var content = "Hello World";
var reqHeaders = new Headers();
reqHeaders.append("Content-Type","text/plain"
reqHeaders.append("Content-Length",content.length.toString());
reqHeaders.append("X-Custom-Header","自定义头");

当然,你也可以使用字面量的形式:

reqHeaders = new Headers({
  "Content-Type": "text/plain","Content-Length": content.length.toString(),"X-Custom-Header": "自定义头",});

接下来就是,头部的内容的检测相关.

console.log(reqHeaders.has("Content-Type")); // true
console.log(reqHeaders.has("Set-Cookie")); // false
reqHeaders.set("Content-Type","text/html");
reqHeaders.append("X-Custom-Header","新增自定义头");
 
console.log(reqHeaders.get("Content-Length")); // 11
console.log(reqHeaders.getAll("X-Custom-Header")); // ["自定义头","新增自定义头"]
 
reqHeaders.delete("X-Custom-Header");
console.log(reqHeaders.getAll("X-Custom-Header")); // []

不过,鉴于安全性的考虑,有时候在多人协作或者子版块管理时,对于头部的限制还是需要的. 这里,我们可以通过 guard 属性,设置 Headers 的相关策略.
guard 通常可以取 "immutable","request","request-no-cors","response","none".
我们这里不探讨全部,仅仅看一下 request 这个选项.
当你设置了 request 之后,如果你设置的 Header 涉及到 forbidden header name (这个是浏览器自动设置的),那么该次操作是不会成功的.
forbidden header name 通常有.

  • Accept-Charset

  • Accept-Encoding

  • Access-Control-Request-Headers

  • Access-Control-Request-Method

  • Connection

  • Content-Length

  • Cookie

  • Cookie2

  • Date

  • DNT

  • Expect

  • Host

  • Keep-Alive

  • Origin

  • Referer

  • TE

  • Trailer

  • transfer-encoding

  • Upgrade

  • Via

对比与 fetch,我们没有办法去设置 Headers的 guard,所以,这只能在 SW 里使用.

Request 操作

Request 的基本用法和 fetch 差不多.

var uploadReq = new Request("/uploadImage",headers: {
    "Content-Type": "image/png",},body: "image data"
});

fetch("/uploadImage",body: "image data"
});

在浏览器里,一切请求都逃不过跨域和不跨域的问题. fetch 也是. 对于跨域的请求,主要的影响还是体现在 Response 中,这 fetch Request 这,没多大影响. 不过,我们需要在 fetch 设置 mode 属性,来表示这是一个跨域的请求.

fetch('https://www.villainhr.com/cors-enabled/some.json',{mode: 'cors'})  
  .then(function(response) {  
    return response.text();  
  })

常用的 mode 属性值有:

  • same-origin: 表示只请求同域. 如果你在该 mode 下进行的是跨域的请求的话,那么就会报错.

  • no-cors: 正常的网络请求,主要应对于没有后台没有设置 Access-Control-Allow-Origin. 话句话说,就是用来处理 script,image 等的请求的. 他是 mode 的认值.

  • cors: 用来发送跨域的请求. 在发送请求时,需要带上.

另外,还有一个关于 cookie 的跨域内容. 在 XHR2 中,我们了解到,withCredentials 这个属性就是用来设置在进行跨域操作时,对不同域的 Server 是否发送本域的 cookie. 一般设置为 omit(不发送). 在 fetch 当中,使用的是 credentials 属性.
credentials 常用取值为:

  • omit: 发送请求时,不带上 cookie. 认值.

  • same-origin: 发送同域请求时,会带上 cookie.

  • include: 只要发送请求,都会带上 cookie.

所以,如果你想发送 ajax 时,带上 cookie,那么你就需要使用 same-origin,如果想在跨域时也带上 cookie,那么就需要 include.

// 跨域请求
fetch('https://www.villainhr.com/cors-enabled/some.json',{mode: 'cors',credentials:'include'})  
  .then(function(response) {  
    return response.text();  
  })

Response 操作

response 应该算和 fetch 最为接近的一个对象. Response 的实际其实就是 fetch 回调函数传回的参数. Response 中比较常用的属性有四个: status,statusText,ok,type.

  • status: 返回的状态码. 100~500+

  • statusText: 返回状态码代表的含义. 比如,返回"ok".

  • ok: 用来检差 status 是否在200和299之间.

  • type: 表示请求是否跨域,或是否出错. 取值为: “basic”,“cors”,“default”,“error” 或
    “opaque”.

fetch('https://www.villainhr.com/cors-enabled/some.json',credentials:'include'})  
  .then(function(response) {  
    // ...
  })

这里,我们主要关心一下 type 上面挂载的一些属性.

  • basic: 同域通信类别. 可以正常的访问 response 的 header(除了 Set-Cookie 头).

  • cors: 跨域通信类别. 一般只能访问以下的头:

    • Cache-Control

    • Content-Language

    • Content-Type

    • Expires

    • Last-Modified

    • Pragma

  • error: 网络错误类别.

  • opaque: 无法理解类别. 当使用 no-cors 发送跨域请求时,会触发.

另外,在 response 上面,还挂载了几个常用的方法: text(),json().

  • text(): 主要用来处理 server 返回的 string 类型数据.

  • josn(): 主要用来处理 server 返回的 json 类型数据.

使用方式都是流式 API.

fetch('https://www.villainhr.com/cors-enabled/some.json')  
  .then(function(res) {  
    res.text().then((text)=>{...})
    res.json().then((obj)=>{...})
  })

基本的内容就是上述内容. 如果想更详细参考的话,请查阅:

This API is so Fetching!

introduction-to-fetch

原文地址:https://www.jb51.cc/ajax/161811.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐