fetch()
允许您发出类似于 XMLHttpRequest (XHR) 的网络请求。主要区别在于 Fetch API 使用 Promise,它具有更简单的 API,可帮助您避免 XMLHttpRequest API 中复杂的回调。
如果您以前从未使用过 Promise,请查看 JavaScript Promise 简介。
基本 Fetch 请求
以下示例分别使用 XMLHttpRequest
和 fetch
实现。我们想要请求一个 URL,获取响应,并将其解析为 JSON。
XMLHttpRequest
XMLHttpRequest
需要两个监听器来处理成功和错误情况,并调用 open()
和 send()
。来自 MDN 文档的示例。
function reqListener () {
const data = JSON.parse(this.responseText);
console.log(data);
}
function reqError (err) {
console.log('Fetch Error :-S', err);
}
const oReq = new XMLHttpRequest();
oReq.onload = reqListener;
oReq.onerror = reqError;
oReq.open('get', './api/some.json', true);
oReq.send();
Fetch
我们的 fetch 请求如下所示
fetch('./api/some.json')
.then(response => {
if (response.status !== 200) {
console.log(`Looks like there was a problem. Status Code: ${response.status}`);
return;
}
// Examine the text in the response
response.json().then(function(data) {
console.log(data);
});
})
.catch(err => {
console.log('Fetch Error :-S', err);
});
fetch()
请求仅需一次调用即可完成与 XHR 示例相同的工作。要处理响应,我们首先检查响应状态是否为 200,然后将响应解析为 JSON。fetch()
请求的响应是一个 Stream 对象,这意味着在我们调用 json()
方法后,将返回一个 Promise。流是异步发生的。
响应元数据
前面的示例显示了 Response 对象的状态,以及如何将响应解析为 JSON。以下是如何处理您可能想要访问的其他元数据,例如标头
fetch('users.json').then(response => {
console.log(response.headers.get('Content-Type'));
console.log(response.headers.get('Date'));
console.log(response.status);
console.log(response.statusText);
console.log(response.type);
console.log(response.url);
});
响应类型
当我们发出 fetch 请求时,响应将被赋予 "basic
"、"cors
" 或 "opaque
" 的 response.type
。这些 类型
显示了资源来自何处,您可以使用它们来确定如何处理响应对象。
当浏览器请求同源上的资源时,响应具有 basic
类型,并且对您可以从响应中查看的内容有限制。
如果请求是针对另一个源上的资源发出的,并且该源返回 CORs 标头,则类型为 cors
。cors
响应类似于 basic
响应,但它们将您可以查看的标头限制为 Cache-Control
、Content-Language
、Content-Type
、Expires
、Last-Modified
和 Pragma
。
opaque
响应来自不返回 CORS 标头的不同源。对于不透明响应,我们将无法读取返回的数据或查看请求的状态,这意味着您无法检查请求是否成功。
您可以为 fetch 请求定义一种模式,以便只有某些请求类型可以解析。您可以设置的模式如下:
same-origin
仅对同源上资产的请求成功,并拒绝所有其他请求。cors
允许对同源上的资产和其他返回适当 CORs 标头的源的请求。cors-with-forced-preflight
在发出任何请求之前执行预检检查。no-cors
旨在向没有 CORS 标头的其他源发出请求,并导致opaque
响应,但如前所述,这在当前窗口全局范围内是不可能的。
要定义模式,请在 fetch
请求中添加一个选项对象作为第二个参数,并在该对象中定义模式
fetch('http://some-site.com/cors-enabled/some.json', {mode: 'cors'})
.then(response => response.text())
.then(text => {
console.log('Request successful', text);
})
.catch(error => {
log('Request failed', error)
});
Promise 链接
promise 的强大功能之一是能够将它们链接在一起。对于 fetch()
,这使您可以在 fetch 请求之间共享逻辑。
如果您正在使用 JSON API,则需要检查每个响应的状态并解析 JSON。您可以通过在单独的函数中定义状态和 JSON 解析(返回 promise),并使用 fetch 请求仅处理最终数据和错误情况来简化代码。
function status (response) {
if (response.status >= 200 && response.status < 300) {
return Promise.resolve(response)
} else {
return Promise.reject(new Error(response.statusText))
}
}
function json (response) {
return response.json()
}
fetch('users.json')
.then(status)
.then(json)
.then(data => {
console.log('Request succeeded with JSON response', data);
}).catch(error => {
console.log('Request failed', error);
});
此示例定义了一个 status
函数,该函数检查 response.status
并返回解析后的 Promise 作为 Promise.resolve()
,或拒绝的 Promise 作为 Promise.reject()
。这是 fetch()
链中调用的第一个方法。
如果 Promise 解析,则脚本随后调用 json()
方法,该方法从 response.json()
调用返回第二个 Promise,并创建一个包含解析后的 JSON 的对象。如果解析失败,则 Promise 被拒绝,并且 catch 语句执行。
此结构允许您在所有 fetch 请求之间共享逻辑,从而使代码更易于维护、阅读和测试。
POST 请求
有时,Web 应用程序需要使用 POST 方法调用 API,并在请求正文中包含一些参数。为此,请在 fetch()
选项中设置 method
和 body
参数
fetch(url, {
method: 'post',
headers: {
"Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
},
body: 'foo=bar&lorem=ipsum'
})
.then(json)
.then(data => {
console.log('Request succeeded with JSON response', data);
})
.catch(error => {
console.log('Request failed', error);
});
使用 fetch 请求发送凭据
要使用凭据(例如 Cookie)发出 fetch 请求,请将请求的 credentials
值设置为 "include"
fetch(url, {
credentials: 'include'
})