目录
[options 对象可以包含的属性](#options 对象可以包含的属性)
[为什么使用Fetch API请求后不直接返回原生的Promise的两个参数形式](#为什么使用Fetch API请求后不直接返回原生的Promise的两个参数形式)
是什么
在Web开发,是实现异步请求的常见方式(与XMLHttpRequest类似)。用于客户端(浏览器)和服务器之间传输数据,实现异步通信。它允许Web页面在不重新加载整个页面的情况下,与服务器交换数据并更新部分页面内容,这种异步处理方式提高了Web应用的交互性和响应速度。
可以说 Fetch API 是 Promise 异步请求处理机制的一个实现。
介绍
Fetch API是浏览器提供的一个用于发起网络请求的API ,它基于Promise设计,它返回一个 Promise 对象,这个对象在请求完成(无论是成功还是失败)时解析为 Response 对象。使得异步请求(异步操作)更加简洁和易于处理。
PS:**Fetch API是浏览器专为JavaScript发起异步请求设计的,**虽然 Fetch API 不是 JavaScript 的内置对象(Fetch API 提供了一个JavaScript接口),但它已经成为现代 JavaScript 开发中处理网络请求的常用方法。(不需要导包即可使用,因为它是浏览器原生支持的 Web API 之一)
特点
- 基于 Promise:Fetch 返回的是一个 Promise 对象,这使得异步处理更加直观和方便。
- 更现代:相比 XMLHttpRequest,Fetch API 提供了简洁的接口,使用起来更加直观和易于理解。
- 更好的错误处理:Fetch API 提供了更好的错误处理机制,可以更容易地捕获和处理网络请求中的错误。
Fetch API 提供了许多与 XMLHttpRequest 功能相同的方法,但是Fetch API提供了更现代、更简洁的语法,并且更加符合Web标准。
发起请求
fetch 函数是 Fetch API 的核心,它通过基于Promise的异步请求机制来发起网络请求并处理响应。
fetch函数
fetch 函数用于向指定的 URL 发起 HTTP 或 HTTPS 请求。你可以指定请求方法(如 GET、POST、PUT、DELETE 等)、请求头、请求体等。
fetch函数可接受两个参数
-
URL(必需):要获取的资源的 URL。这通常是一个字符串,表示资源的地址。
-
options(可选):一个可选的配置对象,包含了请求的各种设置,如方法、头部信息、请求体等。如果不需要额外的配置,这个参数可以省略。
options 对象可以包含的属性
- method:HTTP 请求的方法(如 'GET'、'POST' 等)。
- headers:一个包含了请求头部的对象。
- body:请求体,通常是一个 Blob、BufferSource、FormData、URLSearchParams 或者一个字符串。
- mode:请求的模式,例如 'cors'、'no-cors'、'same-origin' 或 'navigate'。
- credentials:请求是否包含凭证信息(如 cookies 或 HTTP 认证)。
- cache:请求的缓存模式(如 'default'、'no-store'、'reload'、'no-cache'、'force-cache' 或 'only-if-cached')。
- redirect:请求重定向的模式(如 'follow'、'error' 或 'manual')。
- referrer:一个 USVString 指定了请求的 referrer。这可以是一个 URL,一个 'client' 字符串,或者是一个空字符串。
- referrerPolicy:一个指定了用于获取 referrer 的策略的字符串。
- integrity:一个包含了请求的子资源完整性的字符串。
- keepalive:一个布尔值,表示是否应该在网络层保持 TCP 连接打开,即使请求已经完成。
- signal:一个 AbortSignal 对象,允许你使用 AbortController 来中止请求。
options对象可以包含的常用属性的详细代码说明:
javascript
// 引入必要的库(如果需要处理取消请求)
const { AbortController } = require('abort-controller'); // 在Node.js环境中可能需要引入
// 创建一个AbortController实例
const controller = new AbortController();
const { signal } = controller;
// 发起fetch请求
fetch('https://api.example.com/data', {
method: 'POST', // 请求方法
headers: {
'Content-Type': 'application/json', // 请求头
'Authorization': 'Bearer token' // 示例:包含身份验证的token
},
body: JSON.stringify({ key: 'value' }), // 请求体
mode: 'cors', // 请求模式,默认为'cors'
credentials: 'include', // 凭据模式,默认为'omit'
cache: 'no-cache', // 缓存模式,默认为'default'
redirect: 'follow', // 重定向模式,默认为'follow'
referrer: 'no-referrer', // 发送的Referrer头部字段,默认为'client'
referrerPolicy: 'no-referrer', // Referrer Policy,指定如何发送Referrer头部字段
// integrity: 'sha256-...', // 子资源完整性,用于验证响应的内容
signal: signal, // 用于取消请求的AbortSignal对象
// keepalive: true, // 控制是否应保持连接,通常不需要手动设置
})
.then(response => {
// 检查响应状态码
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
// 解析响应体为JSON
return response.json();
})
.then(data => {
// 处理解析后的数据
console.log(data);
})
.catch(error => {
// 处理错误
if (error.name === 'AbortError') {
console.log('Fetch aborted');
} else {
console.error('There has been a problem with your fetch operation:', error);
}
});
// 在某个时间点取消请求
// 例如,在按钮点击事件处理器中
// controller.abort();
简单使用
发起GET请求
fetch函数只有一个参数表示请求地址,表示发起默认的GET请求。
java
fetch('https://api.example.com/data')
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json(); // 解析 JSON 数据
})
.then(data => {
console.log(data); // 在这里处理数据
})
.catch(error => {
console.error('There has been a problem with your fetch operation:', error);
});
发起POST请求和其它请求
发送其它请求将method属性改为对应的请求方式即可。
javascript
const data = { username: 'example', password: 'secret' };
fetch('https://api.example.com/login', {
method: 'POST', // 或者 'PUT'
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
.then(response => response.json())
.then(data => console.log(data))
.catch((error) => {
console.error('Error:', error);
});
使用async/await语法
因使用Fetch API发起请求后,它返回一个 Promise,允许你使用 .then() 或 async/await 语法来处理响应,以下是async/await语法示例:
javascript
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json(); // 或者 await response.text()
console.log(data);
} catch (error) {
console.error('There has been a problem with your fetch operation:', error);
}
}
fetchData();
处理响应
fetch()函数发起一个请求后,它会返回一个Promise。这个Promise解析后(返回一个Promise并被解析也就是第一个 then 方法中总是会被解析成一个 Response 对象 )你会得到一个Response对象。无论 HTTP 请求是否成功(即 HTTP 状态码是否为 2xx)。如果 ok 为 true,你可以继续处理响应体;如果 ok 为 false,可以选择抛出错误,后续在 .catch() 方法中捕获并处理。
使用fetch发起请求后将返回的Promise对象解析为Response对象这种处理方式使我们有了更多的控制权,可以直接检查HTTP响应的状态码和头信息,然后再决定如何处理响应体。
PS:Fetch API 本身并不提供 then 和 catch 这样的方法,因为这些方法是定义在 Promise 对象上的。当你使用 fetch 发起一个网络请求时,它返回的是一个 Promise 对象,这个对象代表了异步操作(网络请求)的最终完成(或失败)及其结果值。
Response对象
Fetch API 中的 fetch() 函数返回一个 Promise 对象,这个 Promise 对象解析(resolve)为一个 Response 对象,这是Fetch API有意为之的设计,旨在提供一种更加底层和灵活的方式来处理HTTP响应。这个Response 对象包含了响应的状态码、状态消息、响应头以及响应体。
使用fetch函数发起请求后返回的 你可以通过调用 Response 对象的方法(如 json()、text()、blob() 等)从Response 对象中提取数据,这些方法也返回 Promise 对象。
总结来说:Promise 是一个代表异步操作最终完成或失败的对象。而 Response 对象则是 Fetch API 用来描述 HTTP 响应的对象。
属性
status
作用:表示响应的HTTP状态码(例如:200, 404等)。
示例:
javascript
fetch('https://api.example.com/data')
.then(response => {
console.log(response.status); // 输出HTTP状态码,如200
});
statusText
作用:提供了一个状态消息,该消息对应于由HTTP状态码表示的状态。例如,"OK"对应于200状态码。
示例:
javascript
fetch('https://api.example.com/data')
.then(response => {
console.log(response.statusText); // 输出状态消息,如"OK"
});
ok
作用:返回一个布尔值,表示请求是否成功(即HTTP状态码是否在200-299范围内)。
示例:
javascript
fetch('https://api.example.com/data')
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response;
});
headers
作用:返回一个Headers对象,包含响应的头部信息。
示例:
javascript
fetch('https://api.example.com/data')
.then(response => {
console.log(response.headers.get('Content-Type')); // 例如,输出 "application/json"
})
.catch(error => {
console.error('Error:', error);
});
Headers对象的属性和方法如下
- constructor :
Headers([init])
- 创建一个新的
Headers
对象。init
可以是一个头部信息的数组(每个元素都是一个[name, value]
对的数组),或者是一个Headers
对象,或者是一个对象(其属性名对应头部名称,属性值对应头部值)。
- 创建一个新的
- append(name, value) :
- 向头部信息集合中添加一个新的头部信息。如果已存在同名的头部信息,则添加一个新的值,而不是替换它。
- delete(name) :
- 从头部信息集合中删除指定的头部信息。
- entries() :
- 返回一个迭代器,允许你遍历头部信息集合中的所有
[name, value]
对。
- 返回一个迭代器,允许你遍历头部信息集合中的所有
- forEach(callback[, thisArg]) :
- 对头部信息集合中的每个头部信息执行一次提供的函数。
- get(name) :
- 返回指定名称的头部信息的第一个值。如果没有找到,则返回
null
。
- 返回指定名称的头部信息的第一个值。如果没有找到,则返回
- getAll(name) :
- 返回一个数组,包含了指定名称的头部信息的所有值。如果没有找到,则返回一个空数组。
- has(name) :
- 返回一个布尔值,指示是否存在指定名称的头部信息。
- keys() :
- 返回一个迭代器,允许你遍历头部信息集合中的所有头部名称。
- set(name, value) :
- 设置指定名称的头部信息的值。如果已存在同名的头部信息,则替换它的值。
- values() :
- 返回一个迭代器,允许你遍历头部信息集合中的所有头部值。
示例:
javascript
// 创建一个新的 Headers 对象
let headers = new Headers();
// 添加头部信息
headers.append('Content-Type', 'application/json');
headers.append('Authorization', 'Bearer token');
// 获取头部信息
console.log(headers.get('Content-Type')); // 输出: "application/json"
// 遍历头部信息
for (let [name, value] of headers.entries()) {
console.log(`${name}: ${value}`);
}
// 输出:
// Content-Type: application/json
// Authorization: Bearer token
// 删除头部信息
headers.delete('Authorization');
// 再次遍历头部信息
for (let [name, value] of headers.entries()) {
console.log(`${name}: ${value}`);
}
// 输出:
// Content-Type: application/json
PS:虽然 Headers
对象的方法(如 append
、set
等)会修改 Headers
对象的状态,但 Headers
对象的任何改变都不会影响已经使用这些头部信息的请求或响应。如果你需要更新一个已发送的请求的头部信息,你需要重新发送该请求。
url
作用:返回请求的URL(如果重定向,则可能是最终重定向到的URL)。
示例:
javascript
fetch('https://api.example.com/data')
.then(response => {
console.log(response.url); // 输出请求的URL,如果有重定向,则可能是重定向后的URL
})
.catch(error => {
console.error('Error:', error);
});
redirected
作用:返回一个布尔值,表示是否经历了重定向。
示例:
javascript
fetch('https://api.example.com/data')
.then(response => {
// 检查请求是否经历了重定向
if (response.redirected) {
console.log('请求被重定向了');
// 在这里你可以进一步处理重定向的情况,比如检查重定向的次数、URL等
} else {
console.log('请求没有被重定向');
}
return response;
});
type
作用:响应的类型(例如,"basic"、"cors"、"error" 或 "opaque")。
示例:
javascript
fetch('https://api.example.com/data')
.then(response => {
console.log(response.type); // 输出响应的类型
})
.catch(error => {
console.error('Error:', error);
});
body
作用:返回一个可读流,表示响应的主体内容。通常,你会使用.json(), .text(), .blob(), .formData(), .arrayBuffer()等方法来解析这个流。
示例:
javascript
fetch('https://api.example.com/data')
.then(response => response.json()) // 解析响应体为JSON
.then(data => {
console.log(data); // 输出解析后的JSON数据
})
.catch(error => {
console.error('Error:', error);
});
方法
text()
作用:将Promise解析为响应体的文本内容,并返回一个Promise。
示例:
javascript
fetch('some-url')
.then(response => response.text())
.then(text => {
console.log(text); // 输出响应体的文本内容
});
json()
作用:将Promise解析为响应体的JSON内容,并返回一个Promise。
示例:
javascript
fetch('some-url')
.then(response => response.json())
.then(data => {
console.log(data); // 输出解析后的JSON数据
});
blob()
作用:将Promise解析为响应体的Blob或File对象,并返回一个Promise。
示例:
javascript
fetch('some-image-url')
.then(response => response.blob())
.then(blob => {
// 处理Blob数据,例如将其转换为ObjectURL并显示在<img>标签中
});
formData()
作用:将Promise解析为响应体的FormData对象(如果响应体是multipart/form-data类型),并返回一个Promise。(FormData 代表表单数据)
示例:
javascript
fetch('https://example.com/some-form-data')
.then(response => response.formData())
.then(formData => {
// 遍历FormData对象
for (let [key, value] of formData.entries()) {
console.log(key, value);
}
})
.catch(error => {
console.error('Error:', error);
});
arrayBuffer()
作用:将Promise解析为响应体的ArrayBuffer对象,并返回一个Promise。(arrayBuffer表示原始的二进制数据缓冲区)
示例:
javascript
fetch('https://example.com/some-binary-data')
.then(response => response.arrayBuffer())
.then(arrayBuffer => {
// 处理ArrayBuffer数据
// 例如,可以使用Uint8Array来访问数据
const uint8Array = new Uint8Array(arrayBuffer);
console.log(uint8Array);
})
.catch(error => {
console.error('Error:', error);
});
clone()
作用:创建一个响应对象的克隆。这在需要多次读取响应体时很有用,因为响应体只能被读取一次。
示例:
javascript
fetch('https://api.example.com/data')
.then(response => {
// 假设我们需要将响应体读取为文本和JSON
const textPromise = response.clone().text();
const jsonPromise = response.json();
return Promise.all([textPromise, jsonPromise]);
})
.then(([text, json]) => {
console.log('Text:', text);
console.log('JSON:', json);
})
.catch(error => {
console.error('Error:', error);
});
代码说明:上面的clone()示例中,创建了一个响应的克隆来读取文本,因为原始的响应体将被用于读取JSON。如果不克隆,尝试在读取JSON后再次读取文本将会失败。
实际使用示例:
javascript
fetch('https://api.example.com/data')
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json(); // 解析 JSON 数据
})
.then(data => {
console.log(data); // 在这里处理数据
})
.catch(error => {
console.error('There has been a problem with your fetch operation:', error);
});
PS:在实际使用Fetch API时,通常会先检查 response.ok 来确定请求是否成功,然后根据需要调用如json()、text()等方法来处理响应体。
为什么使用Fetch API请求后不直接返回原生的Promise的两个参数形式
设计选择解析为一个 Response 对象而不是直接使用原生 Promise 的两个参数(resolve 和 reject)的形式,这种设计的好处是,它给了你更多的控制权。可以直接检查HTTP响应的状态码和头信息,然后再决定如何处理响应体。
主要是出于以下几个原因:
-
更丰富的错误处理:通过返回一个 Response 对象,fetch 提供了更详细的关于请求和响应的信息,而不仅仅是成功或失败。即使请求失败了(比如 404 或 500 错误),fetch 也会返回一个 Response 对象,你可以通过检查其 status 属性来确定是否成功,以及通过 statusText 属性来获取状态消息。这种设计使得开发者能够更精细地处理各种情况。
-
保持一致性:Fetch API 的设计是遵循 Fetch 规范(https://fetch.spec.whatwg.org/),这个规范定义了一个更现代、更强大且更一致的请求/响应模型。在这个模型中,所有的响应都被封装在 Response 对象中,这样可以保持 API 的一致性,使得开发者可以更容易地理解和使用它。
-
链式调用:通过返回一个 Response 对象而不是直接解析或拒绝 Promise,fetch 使得开发者能够更容易地进行链式调用。你可以在一个 then 方法中处理响应,然后在另一个 then 方法中继续处理解析后的数据(比如 JSON 或文本)。这种链式调用的方式使得代码更加清晰和易于维护。
-
兼容性:虽然原生 Promise 的两个参数(resolve 和 reject)的形式在某些情况下可能更直观,但 fetch 的设计是为了与未来的 Web 标准和 API 保持一致。此外,fetch 还提供了与 Service Workers 和其他现代 Web API 更好的集成,这些 API 也使用 Response 对象来表示响应。
-
灵活性:通过返回一个 Response 对象,fetch 提供了更大的灵活性。你可以根据需要检查响应的各种属性(如 headers、type、url 等),并决定如何处理响应。此外,你还可以使用 Response 对象的方法(如 clone()、redirect() 等)来进一步处理响应。