Fetch API 能够执行XMLHttpRequest 对象的所有任务,但更容易使用,接口也更现代化,能够在
Web 工作线程等现代Web 工具中使用。XMLHttpRequest 可以选择异步,而Fetch API 则必须是异步。
Fetch API 是WHATWG 的一个“活标准”(living standard),用规范原文说,就是“Fetch 标准定义请求、
响应,以及绑定二者的流程:获取(fetch)”。
Fetch API 本身是使用JavaScript 请求资源的优秀工具,同时这个API 也能够应用在服务线程
(service worker)中,提供拦截、重定向和修改通过fetch()生成的请求接口。
基本用法
fetch()方法是暴露在全局作用域中的,包括主页面执行线程、模块和工作线程。调用这个方法,
浏览器就会向给定URL 发送请求。
- 分派请求
fetch()只有一个必需的参数input。多数情况下,这个参数是要获取资源的URL。这个方法返回
一个期约:
let r = fetch(‘/bar’);
console.log®; // Promise
URL 的格式(相对路径、绝对路径等)的解释与XHR 对象一样。
请求完成、资源可用时,期约会解决为一个Response 对象。这个对象是API 的封装,可以通过它
取得相应资源。获取资源要使用这个对象的属性和方法,掌握响应的情况并将负载转换为有用的形式,
如下所示:
fetch(‘bar.txt’)
.then((response) => {
console.log(response);
});
// Response { type: “basic”, url: … }
读取响应
读取响应内容的最简单方式是取得纯文本格式的内容,这要用到text()方法。这个方法返回一个
期约,会解决为取得资源的完整内容:
fetch(‘bar.txt’)
.then((response) => {
response.text().then((data) => {
console.log(data);
});
});
// bar.txt 的内容
内容的结构通常是打平的:
fetch(‘bar.txt’)
.then((response) => response.text())
.then((data) => console.log(data));
// bar.txt 的内容
处理状态码和请求失败
Fetch API 支持通过Response 的status(状态码)和statusText(状态文本)属性检查响应状
态。成功获取响应的请求通常会产生值为200 的状态码,如下所示:
fetch(‘/bar’)
.then((response) => {
console.log(response.status); // 200
console.log(response.statusText); // OK
});
请求不存在的资源通常会产生值为404 的状态码:
fetch(‘/does-not-exist’)
.then((response) => {
console.log(response.status); // 404
console.log(response.statusText); // Not Found
});
请求的URL 如果抛出服务器错误会产生值为500 的状态码:
fetch(‘/throw-server-error’)
.then((response) => {
console.log(response.status); // 500
console.log(response.statusText); // Internal Server Error
});
可以显式地设置fetch()在遇到重定向时的行为(本章后面会介绍),不过默认行为是跟随重定向
并返回状态码不是300~399 的响应。跟随重定向时,响应对象的redirected 属性会被设置为true,
而状态码仍然是200:
fetch(‘/permanent-redirect’)
.then((response) => {
// 默认行为是跟随重定向直到最终URL
// 这个例子会出现至少两轮网络请求
// /permanent-redirect ->
console.log(response.status); // 200
console.log(response.statusText); // OK
console.log(response.redirected); // true
});
在前面这几个例子中,虽然请求可能失败(如状态码为500),但都只执行了期约的解决处理函数。
事实上,只要服务器返回了响应,fetch()期约都会解决。这个行为是合理的:系统级网络协议已经成
功完成消息的一次往返传输。至于真正的“成功”请求,则需要在处理响应时再定义。
通常状态码为200 时就会被认为成功了,其他情况可以被认为未成功。为区分这两种情况,可以在
状态码非200~299 时检查Response 对象的ok 属性:
fetch(‘/bar’)
.then((response) => {
console.log(response.status); // 200
console.log(response.ok); // true
});
fetch(‘/does-not-exist’)
.then((response) => {
console.log(response.status); // 404
console.log(response.ok); // false
});
因为服务器没有响应而导致浏览器超时,这样真正的fetch()失败会导致期约被拒绝:
fetch(‘/hangs-forever’)
.then((response) => {
console.log(response);
}, (err) => {
console.log(err);
});
//(浏览器超时后)
// TypeError: “NetworkError when attempting to fetch resource.”
违反CORS、无网络连接、HTTPS 错配及其他浏览器/网络策略问题都会导致期约被拒绝。
可以通过url 属性检查通过fetch()发送请求时使用的完整URL:
// foo.com/bar/baz 发送的请求
console.log(window.location.href); // https://foo.com/bar/baz
fetch(‘qux’).then((response) => console.log(response.url));
// https://foo.com/bar/qux
fetch(‘/qux’).then((response) => console.log(response.url));
// https://foo.com/qux
fetch(‘//qux.com’).then((response) => console.log(response.url));
// https://qux.com
fetch(‘https://qux.com’).then((response) => console.log(response.url));
// https://qux.com