开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情
JavaScript 可以将网络请求发送到服务器,并在需要时加载新信息。
例如,我们可以使用网络请求来:
- 提交订单,
- 加载用户信息,
- 从服务器接收最新的更新,
- ……等。
……所有这些都没有重新加载页面!
对于来自 JavaScript 的网络请求,有一个总称术语 “AJAX”(Asynchronous JavaScript And XML 的简称)。但是,我们不必使用 XML:这个术语诞生于很久以前,所以这个词一直在那儿。
有很多方式可以向服务器发送网络请求,并从服务器获取信息。
fetch() 方法是一种现代通用的方法,那么我们就从它开始吧。旧版本的浏览器不支持它(可以 polyfill),但是它在现代浏览器中的支持情况很好。
基本语法:
let promise = fetch(url, [options])
url—— 要访问的 URL。options—— 可选参数:method,header 等。
没有 options,这就是一个简单的 GET 请求,下载 url 的内容。
浏览器立即启动请求,并返回一个该调用代码应该用来获取结果的 promise。
获取响应通常需要经过两个阶段。
第一阶段,当服务器发送了响应头(response header),fetch 返回的 promise 就使用内建的 Response class 对象来对响应头进行解析。
在这个阶段,我们可以通过检查响应头,来检查 HTTP 状态以确定请求是否成功,当前还没有响应体(response body)。
如果 fetch 无法建立一个 HTTP 请求,例如网络问题,亦或是请求的网址不存在,那么 promise 就会 reject。异常的 HTTP 状态,例如 404 或 500,不会导致出现 error。
我们可以在 response 的属性中看到 HTTP 状态:
status—— HTTP 状态码,例如 200。ok—— 布尔值,如果 HTTP 状态码为 200-299,则为true。
例如:
let response = await fetch(url);
if (response.ok) { // 如果 HTTP 状态码为 200-299
// 获取 response body(此方法会在下面解释)
let json = await response.json();
} else {
alert("HTTP-Error: " + response.status);
}
第二阶段,为了获取 response body,我们需要使用一个其他的方法调用。
Response 提供了多种基于 promise 的方法,来以不同的格式访问 body:
response.text()—— 读取 response,并以文本形式返回 response,response.json()—— 将 response 解析为 JSON 格式,response.formData()—— 以FormData对象(在 下一章 有解释)的形式返回 response,response.blob()—— 以 Blob(具有类型的二进制数据)形式返回 response,response.arrayBuffer()—— 以 ArrayBuffer(低级别的二进制数据)形式返回 response,- 另外,
response.body是 ReadableStream 对象,它允许你逐块读取 body,我们稍后会用一个例子解释它。
例如,我们从 GitHub 获取最新 commits 的 JSON 对象:
let url = 'https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits';
let response = await fetch(url);
let commits = await response.json(); // 读取 response body,并将其解析为 JSON 格式
alert(commits[0].author.login);
也可以使用纯 promise 语法,不使用 await:
fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits')
.then(response => response.json())
.then(commits => alert(commits[0].author.login));
要获取响应文本,可以使用 await response.text() 代替 .json():
let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits');
let text = await response.text(); // 将 response body 读取为文本
alert(text.slice(0, 80) + '...');
作为一个读取为二进制格式的演示示例,让我们 fetch 并显示一张 “fetch” 规范 中的图片(Blob 操作的有关内容请见 Blob):
let response = await fetch('/article/fetch/logo-fetch.svg');
let blob = await response.blob(); // 下载为 Blob 对象
// 为其创建一个 <img>
let img = document.createElement('img');
img.style = 'position:fixed;top:10px;left:10px;width:100px';
document.body.append(img);
// 显示它
img.src = URL.createObjectURL(blob);
setTimeout(() => { // 3 秒后将其隐藏
img.remove();
URL.revokeObjectURL(img.src);
}, 3000);
重要:
我们只能选择一种读取 body 的方法。
如果我们已经使用了 response.text() 方法来获取 response,那么如果再用 response.json(),则不会生效,因为 body 内容已经被处理过了。
let text = await response.text(); // response body 被处理了
let parsed = await response.json(); // 失败(已经被处理过了)