自 1998 年发布 IE5 以来,我们可以选择使用 XMLHttpRequest(XHR)在浏览器中进行异步网络调用。
几年后,GMail 和其他应用大量使用它,并使这种方法如此流行,以至于它不得不有一个名字:AJAX。
直接使用 XMLHttpRequest 一直很痛苦,一些开发者将它抽象成库,尤其是 jQuery 围绕它构建了自己的辅助函数:
jQuery.ajax()
jQuery.get()
jQuery.post()
- etc
它们在使其更易于访问方面产生了巨大的影响,特别是在确保所有功能都能在较旧的浏览器上运行。
Fetch API 已被标准化为异步网络请求的现代方法,并使用 Promises 作为构建块。
以下是目前浏览器对 Fetch API 的支持:
可以看到,Fetch 对除 IE 以外的主流浏览器都有很好的支持。
GitHub 发布的 fetch polyfill 允许我们在任何浏览器上使用 fetch。
使用 Fetch 对 GET 请求非常简单:
fetch('/file.json')
fetch 将发出一个 HTTP 请求来获取 file.json
同域上的资源。
如您所见,fetch
函数在全局 window
范围内可用。
Tips:您可以使用 JSONPlaceholder 提供的 API 进行测试。
现在让我们让它更有用一点,让我们看看文件的内容是什么:
fetch('./file.json')
.then((response) => response.json())
.then((data) => console.log(data))
调用 fetch()
将返回一个 promise。然后,我们可以通过传递带有 promise 的 then()
方法的处理程序来等待 promise 解析。
该处理程序接收 fetch promise 的返回值,这是一个 Response 对象。
我们将在下一节中详细了解这个对象。
由于 fetch()
返回了一个 promise,我们可以使用 promise 的 catch
方法来拦截请求执行期间发生的任何错误,以及在 then
回调中完成的处理:
fetch('./file.json')
.then((response) => {
// ...
})
.catch((err) => console.error(err))
捕获错误的另一种方法是在第一个 then
中管理错误:
fetch('./file.json')
.then((response) => {
if (!response.ok) {
throw Error(response.statusText)
}
return response
})
.then((response) => {
// ...
})
fetch()
调用返回的响应对象包含有关请求和网络请求响应的所有信息。
以下是一些元数据:
通过访问 response
对象上的 headers
属性,可以查看请求返回的 HTTP 头:
fetch('./file.json').then((response) => {
console.log(response.headers.get('Content-Type'))
console.log(response.headers.get('Date'))
})
status
属性是一个整数,表示 HTTP 响应状态。
例如:
- 200-299 为成功状态
- 301、302、303、307 或 308 是重定向
fetch('./file.json').then((response) => console.log(response.status))
推荐:常见的 HTTP 状态码
statusText
是表示响应状态消息的属性。如果请求成功,则状态为 OK。
fetch('./file.json').then((response) => console.log(response.statusText))
url 表示我们获取的属性的完整 URL。
fetch('./file.json').then((response) => console.log(response.url))
响应有一个正文,可以使用多种方法访问:
text()
以字符串形式返回正文json()
将正文作为 JSON 解析的对象返回blob()
将正文作为 Blob 对象返回formData()
将正文作为 FormData 对象返回arrayBuffer()
将正文作为 ArrayBuffer 对象返回
所有这些方法都返回一个 Promise。例如:
fetch('./file.json')
.then((response) => response.text())
.then((body) => console.log(body))
fetch('./file.json')
.then((response) => response.json())
.then((body) => console.log(body))
也可以使用 ES8 的异步函数编写相同的内容:
;(async () => {
const response = await fetch('./file.json')
const data = await response.json()
console.log(data)
})()
Request 对象表示一个资源请求,通常使用 new Request()
API 创建。
例如:
const req = new Request('/api/todos')
Request 对象提供了几个只读属性来检查资源请求的详细信息,包括:
method
— 请求的方法(GET、POST 等)url
— 请求的 URLheaders
— 请求的关联 headers 对象referrer
— 请求的引用者cache
— 请求的缓存模式(例如,default
、reload
和no-cache
)
并公开了几种方法,包括 json()
、text()
和 formData()
来处理请求的正文。
能够设置 HTTP 请求头是至关重要的,并且 fetch 使我们能够使用 Headers 对象完成这项工作:
const headers = new Headers()
headers.append('Content-Type', 'application/json')
或者:
const headers = new Headers({
'Content-Type': 'application/json'
})
要将 headers 附加到请求,我们使用 Request 对象,并将其传递给 fetch()
,而不是传递 URL。
fetch('./file.json')
替换为:
const request = new Request('./file.json', {
headers: new Headers({
'Content-Type': 'application/json'
})
})
fetch(request)
Headers 对象不限于设置值,但我们也可以查询它:
headers.has('Content-Type')
headers.get('Content-Type')
我们可以删除之前设置的 header:
headers.delete('X-My-Custom-Header')
Fetch 还允许在请求中使用任何其他 HTTP 方法:POST、PUT、DELETE 或 OPTIONS 等。
在请求的 method
属性中指定方法,并在请求头和请求体中传递其他参数:
POST 请求示例:
const options = {
method: 'post',
headers: {
'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
body: 'name=O.O&test=1'
}
fetch(url, options).catch((err) => {
console.error('Request failed', err)
})
在引入 fetch 之后的几年中,一旦打开请求,就无法中止。
现在,由于引入了 AbortController
和 AbortSignal
,我们可以使用通用 API 来通知中止事件。
通过将 signal
作为 fetch 参数传递来集成此 API:
const controller = new AbortController()
const signal = controller.signal
fetch('./file.json', { signal })
您可以设置在 fetch 请求启动 5 秒后触发中止事件的超时,以取消该请求:
setTimeout(() => controller.abort(), 5 * 1000)
如果 fetch 已经返回,调用 abort()
不会导致任何错误。
当出现中止信号时,fetch 将使用名为 AbortError
的 DOMException
拒绝 promise:
fetch('./file.json', { signal })
.then((response) => response.text())
.then((text) => console.log(text))
.catch((err) => {
if (err.name === 'AbortError') {
console.error('Fetch aborted')
} else {
console.error('Another error', err)
}
})
我在另一篇文章分享了 XHR、Axios 以及今天的主题 Fetch API 如何取消网络请求,如果您想了解,可以查看取消已发送的网络请求。
到这里,您已经基本了解了 Fetch API 如何使用。您可以在 👇 下面查看更多关于 Fetch API 的详细内容。