本文摘至: please call me HRphp
随着前端异步的发展, XHR 这种耦合方式的书写不利于前端异步的 Promise 回调. 并且,写起来也是很复杂. fetch API 原本是在 SW(ServiceWorkers) 中提出的, 不过, 后面以为好用, 就把他挂载到 window 对象下. 这样, 在前端的正常通讯中, 咱们也能够直接调用. 但, fetch 毕竟比较新, 看一下他的兼容性.html
在 PC 端上, 就 FF, Opera 和 Chrome 比较 fashion. mobile 的话, 基本上是不能用的. 固然, 前端一直是个拥抱变化的职业, 官方已经有一个现成的 polyfill 可使用. 这样的话, 就不必过多担忧. 前端
每用到一个新的 feature, 咱们首先得知道他能不能用. Modernizr 这个库作的挺好的. 这里, 咱们简单的了解一下就 ok 了.jquery
let isFetch = window.fetch?true:false;
能够说, fetch 就是 ajax + Promise. 使用的方式和 jquery 提供的 $.ajax() 差很少.git
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 的几个特色.github
then()web
catch()ajax
json()json
then 和 catch 是 promise 自带的两个方法, 我这里就很少说了. 咱们来看一下,json 是干吗的. api
由于返回回来的数据不只仅包括后台的返回的 Text 内容, 还有一些 Headers. 因此在, then 方法里面返回来的 res 实际上并非咱们在业务中想要的内容. 就和在 XHR 里返回数据是一个道理, 咱们最终要的是 responseText
这个数据. 而 json() 方法实际作的事情,就是调用 JSON.parse() 处理数据, 而且返回一个新的 Promise. 看一下 polyfill 源码就应该了解.
this.json = function() { return this.text().then(JSON.parse) }
上面的 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 的操做无非就是 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 的基本用法和 fetch 差很少.
var uploadReq = new Request("/uploadImage", { method: "POST", headers: { "Content-Type": "image/png", }, body: "image data" }); fetch("/uploadImage", { method: "POST", headers: { "Content-Type": "image/png", }, 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 应该算和 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', {mode: 'cors',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)=>{...}) })
基本的内容就是上述内容. 若是想更详细参考的话, 请查阅: