JavaScript 通过XMLHttpRequest(XHR)来执行异步请求,设计上不符合职责分离原则,将输入、输出和用事件来跟踪的状态混杂在一个对象里。而且,基于事件的模型与最近JavaScript流行的Promise以及基于生成器的异步编程模型不太搭。新的 Fetch API打算修正上面提到的那些缺陷。
接着上一篇 重拾Ajax,继续一探异步请求的接班人Fetch API…
概念和用法
Fetch 提供了对 Request
和 Response
(以及其他与网络请求有关的)对象通用的定义。它之后能够被使用到很多场景中:service workers、Cache API、其他处理请求和响应的方式,甚至任何需要生成自己的响应的方式。参考资料WHATWG Fetch 规范 和 MDN FetchAPI。
Fetch 是一个很先进的概念,类似于 XMLHttpRequest。它提供了很多 XMLHttpRequest 拥有的功能,不过它被设计成具有更强的可扩展性和更高效。
Chrome, Opera, Firefox
和 Android
浏览器的最新版本都支持Fetch API。 对于不支持的浏览器,你可以借助于fetch-polyfill来提供辅助实现。
fetch() 方法用于发起获取资源的请求。它返回一个 promise,这个 promise 会在请求响应后被 resolve,并传回 Response 对象。
认识fetch之前,先来介绍一下与fetch相关的三个对象 Request、Body、Response、Headers
Headers
请求头对象,Fetch API 的Headers类允许你去对HTTP request
和 response
的headers执行各种操作。 这些操作包括:检索, 设置, 添加和删除。 一个Headers类里包含一个header列表, 它的初始值为空或者是零个或多个键值对。你可以使用 append()方法添加, 这个类中所有的方法, 其 header的名字顺序匹配并不区分大小写。MDN
方法append()
添加一个header信息delete()
删除指定的headerentries()
返回headers对象中的所有键值对,是一个 iterator 对象get()
从Headers对象中返回指定的值getAll()
返回全部的headerhas()
检测指定的header,返回布尔值keys()
返回所有的header的键,是一个iterator对象set()
修改或添加headervalues()
返回所有的header的值 ,是一个iterator对象
可以是一个简单的多映射的名-值表
var content = "Hello World"; |
也可以是一个json对象
reqHeaders = new Headers({ |
Headers的内容可以被检索myHeaders = new Headers({
"Content-Type": "text/plain",
"Content-Length": content.length.toString(),
"X-Custom-Header": "ProcessThisImmediately",
});
console.log(myHeaders.has("Content-Type")); // true
console.log(myHeaders.has("Set-Cookie")); // false
myHeaders.set("Content-Type", "text/html");
myHeaders.append("X-Custom-Header", "AnotherValue");
console.log(myHeaders.get("Content-Length")); // 11
console.log(myHeaders.getAll("X-Custom-Header")); // ["ProcessThisImmediately", "AnotherValue"]
myHeaders.delete("X-Custom-Header");
console.log(myHeaders.getAll("X-Custom-Header")); // [ ]
fetch(myRequest).then(function(response) {
if(response.headers.get("content-type") === "application/json") {
return response.json().then(function(json) {
// process your JSON further
});
} else {
console.log("Oops, we haven't got JSON!");
}
});
Request
FetchAPI的资源请求对象MDN
构造器创建一个实例var req = new Request('data.json', {
method:'POST',
headers:{},
body:new FormData(document.getElementById('login-form')),
cache:'default',
})
属性
method
请求的方法POST/GET等url
请求的地址headers
请求头(可以是Headers对象,也可是JSON对象)context
请求的上下文referrer
指定请求源地址mode
请求的模式(是跨域cors还是正常请求no-cors)credentials
跨域请求时,是否携带cookie信息(omit跨域携带/same-origin同源携带)redirect
重定向integrity
一个散列值,用于检验请求资源的完整性MDNcache
是否缓存这个请求
方法
clone()
复制一个当前request对象的实例
Body
Fetch mixin 对象,提供了关联 response/request 中 body 的方法,可以定义它的文档类型以及请求如何被处理。
Request
和 Response
对象都实现了Body的接口,所以都拥有Body的方法和属性,用于指定请求体中的body或响应体的内容的数据类型(arrayBuffer/blob
/json/text
) 主要是做数据类型的转换。
属性
bodyUsed
用于判断是否在响应体中是否设置过body读取类型
方法
arrayBuffer()
将响应流转换为buffer数组的promise对象,并将bodyUsed状态改为已使用blob()
将响应流转换为大的二进制的promise对象,并将bodyUsed
状态改为已使用,一般用于文件读取(下载大文件或视频)formData()
将响应流转换为formData的promise对象,并将bodyUsed状态改为已使用json()
将响应流转换为json的promise对象,并将bodyUsed状态改为已使用text()
将响应流转换为文本字符串的promise对象,并将bodyUsed状态改为已使用
Response
FetchAPI的响应对象MDN
属性(只读)
type
响应的类型 basic/cors等url
包含Response的URL.useFinalURL
包含了一个布尔值来标示这是否是该Response的最终URLstatus
响应的状态码 1xx-5xxok
表示响应成功statusText
状态码的信息headers
响应头的Headers对象bodyUsed
是否设置过响应内容的类型
方法
clone()
创建一个Response对象的克隆error()
返回一个绑定了网络错误的新的Response对象redirect()
用另一个URL创建一个新的 response.
Fetch 语法 和 示例
语法
fetch('api/data.json', { |
mode
no-cors
允许来自CDN的脚本、其他域的图片和其他一些跨域资源,但是首先有个前提条件,就是请求的method只能是”HEAD”,”GET”或者”POST”。此外,任何 ServiceWorkers 拦截了这些请求,它不能随意添加或者改写任何headers,除了这些。第三,JavaScript不能访问Response中的任何属性,这保证了 ServiceWorkers 不会导致任何跨域下的安全问题而隐私信息泄漏。cors
通常用作跨域请求来从第三方提供的API获取数据。这个模式遵守CORS协议。只有有限的一些headers被暴露给Response对象,但是body是可读的。same-origin
如果一个请求是跨域的,那么返回一个简单的error,这样确保所有的请求遵守同源策略。
cache
default
缓存相同的请求no-store
不缓存任何请求reload
创建一个正常的请求,并用响应更新HTTP缓存no-cache
如果HTTP缓存中有响应,并且不是正常请求,则Fetch创建条件请求。然后,它使用响应更新HTTP缓存。force-cache
Fetch使用HTTP缓存中与请求匹配的任何响应,不管是否过期。如果没有响应,则会创建正常请求,并使用响应更新HTTP缓存。only-if-cached
Fetch使用HTTP缓存中与请求匹配的任何响应,不管是否过期。如果没有响应,则返回网络错误。 (只有当请求的模式为“same-origin”时,才能使用任何缓存重定向,假设请求的重定向模式为“follow”,重定向不会违反请求的模式)。
如果header中包含名称为“If-Modified-Since”
,“If-None-Match”
,“If-Unmodified-Since”
,“If-Match”
和“If-Range”
之一,如果是“default”
,fetch 会将 cache
自动设置为 “no-store”
。
Fetch 示例
var myHeaders = new Headers(); |
简单封装
前面有了ajax的封装过程,fetch的封装就更简单了,因为fetch()方法本身返回的是promise对象,那就不需要使用promise再包装了,代码也简洁很多。
class AjaxFetch{ |
使用var api = {
news: http('api/d1.json'),
users: http('api/d2.json')
}
//get
api.news.get({uname:'xxx', pwd:123}).then(res=>{
console.log(res);
}).catch(err=>{
console.log(err);
})
//post
var frmData = new FormData(document.getElementById('frm1'));
api.news.post(frmData).then(res=>{
console.log(res);
}).catch(err=>{
console.log(err);
})
//类似$.ajax
http({
url:'api/d1.json',
method:'POST',
headers:{'Content-Type':'multipart/form-data; boundary=----'+new Date().getTime()},
data: new FormData(document.getElementById('frm1'))
}).then(res=>{
console.log(res)
debugger;
})
结合Async
async function test2(){ |