fetch 教程
转载自:http://blog.csdn.net/renfufei/article/details/51494396
AJAX半遮半掩的底层API是饱受诟病的一件事情. XMLHttpRequest 并不是专为Ajax而设计的. 虽然各种框架对 XHR 的封装已经足够好用, 但我们可以做得更好。更好用的API是 fetch
。下面简单介绍 window.fetch
方法, 在最新版的 Firefox 和 Chrome 中已经提供支持。
XMLHttpRequest
在我看来 XHR 有点复杂, 我不想解释为什么“XML”是大写,而“Http”是“骆峰式”写法。使用XHR的方式大致如下:
// 获取 XHR 非常混乱! if (window.XMLHttpRequest) { // Mozilla, Safari, ... request = new XMLHttpRequest(); } else if (window.ActiveXObject) { // IE try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {} } } // 打开连接, 发送数据. request.open("GET", "https://davidwalsh.name/ajax-endpoint", true); request.send(null);
request.onreadystatechange = function () {
if (request.readyState === 4 && request.status === 200) {
success(request.responseText)
} else {
}
}
我们可以看出, XHR 其实是很杂乱的; 当然, 通过 JavaScript 框架可以很方便地使用XHR。
fetch 安装
为了解决 fetch 的兼容性,我们使用 Fetch Polyfill 的版本 whatwg-fetch。
npm install --save whatwg-fetch
import "whatwg-fetch"
webpack 项目增加:entry: ["whatwg-fetch", ...]
fetch
的基本使用
fetch
是全局量 window
的一个方法, 第一个参数是URL:
// url (必须), options (可选)
fetch("/some/url", {
method: "get"
}).then(function(response) {
}).catch(function(err) {
// 出错了;等价于 then 的第二个参数,但这样更好用更直观 :(
});
和 Battery API 类似, fetch API 也使用了 JavaScript Promises 来处理结果/回调:
// 链式处理,将异步变为类似单线程的写法: 高级用法.
fetch("/some/url").then(function(response) {
return //... 执行成功, 第1步...
}).then(function(returnedValue) {
// ... 执行成功, 第2步...
}).catch(function(err) {
// 中途任何地方出错...在此处理 :(
});
如果你还不习惯 then
方式的写法,那最好学习一下,因为很快就会全面流行。
请求头(Request Headers)
自定义请求头信息极大地增强了请求的灵活性。我们可以通过 new Headers()
来创建请求头:
// 创建对象时设置初始化信息
var headers = new Headers({
"Content-Type": "text/plain",
"X-My-Custom-Header": "CustomValue"
}); // 添加(append)请求头信息 headers.append("Content-Type", "text/plain"); headers.append("X-My-Custom-Header", "CustomValue"); // 判断(has), 获取(get), 以及修改(set)请求头的值 headers.has("Content-Type"); // true headers.get("Content-Type"); // "text/plain" headers.set("Content-Type", "application/json"); // 删除某条请求头信息(a header) headers.delete("X-My-Custom-Header");
headers 可以使用的方法包括: append, has, get, set, 以及 delete 。需要创建一个 Request
对象来包装请求头:
var request = new Request("/some-url", {
headers: new Headers({
"Content-Type": "text/plain"
})
});
fetch(request).then(function(response) { /* handle response */ });
下面介绍 Request 和 Response 的使用方法!
Request 简介
Request 对象表示一次 fetch 调用的请求信息。传入 Request 参数来调用 fetch, 可以执行很多自定义请求的高级用法:
method
- 支持GET
,POST
,PUT
,DELETE
,HEAD
url
- 请求的 URLheaders
- 对应的Headers
对象referrer
- 请求的引用者(例如:client)mode
- 是否允许跨域请求,以及哪些响应的属性是可读的。可选值:cors
:(默认),允许跨域请求,将遵守 CORS 协议。no-cors:该模式允许来自 CDN 的脚本、其他域的图片和其他一些跨域资源。前提条件是请求的 method 只能是 HEAD、GET 或 POST。
此外,如果 ServiceWorkers 拦截了这些请求,它不能随意添加或者修改除这些之外 Header 属性。第三,js 不能访问 Response 对象
中的任何属性,这确保了跨域时 ServiceWorkers 的安全和隐私信息泄露问题。
same-origin:如果是一个跨域请求,将返回一个 error。
navigate:支持导航的模式,仅用于 HTML 导航。
credentials
- 设置 cookies 是否随请求一起发送。可选值:omit:(默认),不发送 Cookie。
same-origin:同域下自动发送 Cookie。
include:始终发送 Cookie,即使是跨域。
redirect
- 定义重定向处理方式。可选值:follow(默认), error, manual。integrity
- 子资源完整性值。cache
- 设置缓存模式。可选值:default:浏览器在其 HTTP 缓存中查找匹配的请求。
a. 如果匹配并且是新鲜的,它将从缓存中返回。
b. 如果存在匹配但已失效,则浏览器将向远程服务器发出有条件的请求。如果服务器指出资源没有改变,它将从缓存中返回。
否则资源将从服务器下载并且缓存将被更新。
c. 如果没有匹配,浏览器将发出正常的请求,并且下载的资源更新缓存。
no-store:浏览器从远程服务器获取资源,而不先查看缓存,并且不会使用下载的资源更新缓存。
reload:浏览器从远程服务器获取资源,而不先查看缓存,但随后将使用下载的资源更新缓存。
no-cache:浏览器在其 HTTP 缓存中查找匹配的请求。
a. 如果匹配,新鲜或陈旧,浏览器将向远程服务器发出有条件的请求。如果服务器指出资源没有改变,它将从缓存中返回。
否则资源将从服务器下载并且缓存将被更新。
b. 如果没有匹配,浏览器将发出正常的请求,并用下载的资源更新缓存。
force-cache:浏览器在其 HTTP 缓存中查找匹配的请求。
a. 如果有匹配,新鲜或陈旧,它将从缓存中返回。
b. 如果没有匹配,浏览器将发出正常的请求,并用下载的资源更新缓存。
only-if-cached:浏览器在其 HTTP 缓存中查找匹配的请求。只能用在 mode 为 same-origin 的情况下
a. 如果匹配,新鲜或陈旧,将从缓存中返回。
b. 如果没有匹配,浏览器将返回一个错误。
Request
的示例如下:
var request = new Request("/users.json", {
method: "POST",
mode: "cors",
redirect: "follow",
headers: new Headers({
"Content-Type": "text/plain"
})
});
// 使用!
fetch(request).then(function() { /* handle response */ });
只有第一个参数 URL 是必需的。在 Request
对象创建完成之后, 所有的属性都变为只读属性. 请注意, Request
有一个很重要的 clone
方法, 特别是在 Service Worker API 中使用时 —— 一个 Request 就代表一串流(stream), 如果想要传递给另一个 fetch
方法,则需要进行克隆。
fetch
的方法签名(signature,可理解为配置参数), 和 Request
很像, 示例如下:
fetch("/users.json", {
method: "POST",
mode: "cors",
redirect: "follow",
headers: new Headers({
"Content-Type": "text/plain"
})
}).then(function() { /* handle response */ });
因为 Request 和 fetch 的签名一致, 所以在 Service Workers 中, 你可能会更喜欢使用 Request 对象。关于 ServiceWorker 的相关博客请等待后续更新!
提交表单数据(Posting Form Data)
另一种常用的 AJAX 调用是提交表单数据 —— 示例代码如下:
fetch("/submit", {
method: "post",
body: new FormData(document.getElementById("comment-form"))
});
提交 JSON 的示例如下:
fetch("/submit-json", {
method: "post",
body: JSON.stringify({
email: "huang@163.com"
name: "jim"
})
});
Response 简介
Response 代表响应, fetch 的 then
方法接收一个 Response
实例, 当然你也可以手动创建 Response
对象 —— 比如在 service workers 中可能会用到. Response 可以配置的参数包括:
type
- 类型,支持:basic
,cors
url - 响应的 URL
useFinalURL
- Boolean 值, 说明这是否是响应的最终 URLstatus
- 状态码 (例如:200
,404
, 等等)ok
- Boolean值,代表响应是否成功(status 值在 200-299 之间)statusText
- 与状态码相对应的状态值(例如:OK为200
)headers
- 与响应相关联的 Headers 对象.- redirected - 指示响应是否是重定向的结果。也就是说,它的 URL 列表有多条目录。
// 在 service worker 测试中手动创建 response
// new Response(BODY, OPTIONS)
var response = new Response(".....", {
ok: false,
status: 404,
url: "/"
});
// fetch 的 `then` 会传入一个 Response 对象
fetch("/")
.then(function(responseObj) {
console.log("status: ", responseObj.status);
});
Response
提供的方法如下:
clone()
- 创建一个 Response 对象的克隆.error()
- 返回一个与网络错误相关的新 Response 对象.redirect()
- 重定向,使用新的 URL 创建新的 response 对象..arrayBuffer()
-返回一个 resolve 是 ArrayBuffer 的 promise 对象。
blob()
- 返回一个 resolve 是 Blob 的 promise 对象。formData()
- 返回一个 resolve 是 FormData 的 promise 对象。json()
- 返回一个 resolve 是 JSON 的 promise 对象。text()
- 返回一个 resolve 是文本的 promise 对象。
处理 JSON响应
假设需要请求 JSON —— 回调结果对象 response 中有一个json()
方法,用来将原始数据转换成 json 对象:
fetch("https://davidwalsh.name/demo/arsenal.json").then(function(response) {
// 转换为 JSON
return response.json();
}).then(function(j) {
// 现在, `j` 是一个 json 对象
console.log(j);
});
当然这很简单 , 只是封装了 JSON.parse(jsonString)
而已, 但 json
方法还是很方便的。
处理基本的Text / HTML响应
JSON 并不总是理想的请求/响应数据格式, 那么我们看看如何处理 HTML或文本结果:
fetch("/next/page")
.then(function(response) {
return response.text();
}).then(function(text) {
// <!DOCTYPE ....
console.log(text);
});
如上面的代码所示, 可以在 Promise 链式的 then
方法中, 先返回 text()
结果 ,再获取 text 。
处理Blob结果
如果你想通过 fetch 加载图像或者其他二进制数据, 则会略有不同:
fetch("flowers.jpg")
.then(function(response) {
return response.blob();
})
.then(function(imageBlob) {
document.querySelector("img").src = URL.createObjectURL(imageBlob);
});
响应 Body mixin 的 blob()
方法处理响应流(Response stream), 并且将其读完。
未完的故事(Unwritten Story)
fetch
是个很实用的API , 当前还不允许取消请求, 这使得很多程序员暂时不会考虑它。
新的 fetch
API 比起 XHR 更简单也更智能。毕竟,它就是专为AJAX而设计的, 具有后发优势. 而我已经迫不及待地使用了, 即使现在兼容性还不是那么好!
fetch 文档
https://github.com/github/fetch
https://translate.google.com/translate?hl=zh-CN&sl=en&u=https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API&prev=search