fetch() 允许您发出类似于 XMLHttpRequest (XHR) 的网络请求。主要区别在于,Fetch API 使用 Promise,其 API 更简单,可帮助您避免 XMLHttpRequest API 中复杂的 callback。
如果您之前从未使用过 Promise,请参阅 JavaScript Promise 简介。
基本 Fetch 请求
以下示例先使用 XMLHttpRequest 实现,然后使用 fetch 实现。我们希望请求一个网址,获取响应,并将其解析为 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('./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);
});
响应类型
当我们发出提取请求时,响应将获得 response.type“basic”“cors”或“opaque”。这些 types 会显示资源的来源,您可以使用它们来确定如何处理响应对象。
当浏览器请求同一来源的资源时,响应具有 basic 类型,并对您可以从响应中查看的内容施加了限制。
如果请求针对的是其他源上的资源,并且该源返回 CORs 标头,则类型为 cors。cors 响应与 basic 响应类似,但它们会将您可以查看的标头限制为 Cache-Control、Content-Language、Content-Type、Expires、Last-Modified 和 Pragma。
opaque 响应来自不返回 CORS 标头的其他来源。对于不透明响应,我们将无法读取返回的数据或查看请求的状态,这意味着您无法检查请求是否成功。
您可以为提取请求定义模式,以便仅解析特定请求类型。您可以设置以下模式:
same-origin仅对同源素材资源的请求成功,并拒绝所有其他请求。cors允许请求同一源以及返回适当 COR 标头的其他源上的资源。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(),这可让您在提取请求之间共享逻辑。
如果您使用的是 JSON API,则需要检查状态并解析每个响应的 JSON。您可以通过在返回 promise 的单独函数中定义状态和 JSON 解析来简化代码,并使用提取请求仅处理最终数据和错误情况。
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 语句。
这种结构可让您在所有提取请求中共享逻辑,从而使代码更易于维护、阅读和测试。
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);
});
随提取请求一起发送凭据
如需使用 Cookie 等凭据发出提取请求,请将请求的 credentials 值设置为 "include":
fetch(url, {
credentials: 'include'
})