http 请求系列
http request-01-XMLHttpRequest XHR 简单介绍
http request-01-XMLHttpRequest XHR 标准
Ajax 详解-01-AJAX(Asynchronous JavaScript and XML)入门介绍
http 请求-04-promise 对象 + async/await
fetch
跨网络异步获取资源的功能以前是使用XMLHttpRequest对象实现的,Fetch API提供了更好的替代方案,可以很容易的被其他技术使用(如Servise Workers)
fetch,说白了,就是XMLHttpRequest的一种替代方案。
如果有人问你,除了Ajax获取后台数据之外,还有没有其他的替代方案?
你就可以回答,除了XMLHttpRequest对象来获取后台的数据之外,还可以使用一种更优的解决方案fetch。
fetch的支持性还不是很好,但是在谷歌浏览器中已经支持了fetch
返回 promise
Fetch API提供了一个全局的fetch()方法,该方法会返回一个Promise
当fetch请求接收到一个代表错误的状态码时(如404、500),返回的Promise不会被标记为reject,而是被标记为resolve,但是会将response的ok属性设置为false。
只有当网络错误或请求被阻止时才会被标记为reject状态
js
fetch('https://127.0.0.1/125.jpg').then(function(res){
if(res.ok) {
return res.blob();
}else {
console.log('服务器响应出错了'); // 资源404、服务器500等
}
}).catch(function(err){
console.log('Network response was not ok.'); // 网络出错
})
为什么需要 js fetch,解决了 ajax 的什么问题?
fetch
API 是为了解决传统的 XMLHttpRequest
(XHR) 在使用过程中存在的一些问题和局限性。
fetch
提供了一个更现代化和简洁的方式来进行网络请求。
以下是 fetch
解决的一些 AJAX 的问题:
1. 更简洁的 API 设计
- XHR : 使用
XMLHttpRequest
进行网络请求时,需要编写相对复杂和冗长的代码来处理各种情况。
设置请求方法、URL、请求头、监听状态变化等都需要多个步骤。
javascript
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(JSON.parse(xhr.responseText));
} else if (xhr.readyState === 4) {
console.error('Request failed');
}
};
xhr.send();
-
Fetch :
fetch
通过一个简单的函数调用来实现相同的功能,并且支持Promise
,代码更简洁和易读。javascriptfetch('https://api.example.com/data') .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Request failed', error));
2. 基于 Promise 的设计
-
XHR :
XMLHttpRequest
的回调方式容易导致"回调地狱"(回调嵌套过多,代码难以维护)。虽然可以使用Promise
包装 XHR,但这是额外的工作量。 -
Fetch :
fetch
天生支持Promise
,使得处理异步操作更为自然和直观。它支持链式调用,可以很好地处理成功和错误的情况。结合async
/await
,代码结构更加清晰。javascriptasync function getData() { try { const response = await fetch('https://api.example.com/data'); const data = await response.json(); console.log(data); } catch (error) { console.error('Request failed', error); } }
3. 更好的流媒体支持
-
XHR : 对于处理流媒体或分块传输的数据,
XMLHttpRequest
的处理方式较为复杂,需要手动操作数据块。 -
Fetch :
fetch
API 更好地支持ReadableStream
和流媒体。你可以直接处理流媒体响应,逐块读取数据,这在处理大型文件或长连接时非常有用。javascriptfetch('https://example.com/stream') .then(response => { const reader = response.body.getReader(); return reader.read(); }) .then(({ done, value }) => { if (!done) { console.log('Received chunk', value); } });
4. 内置的 JSON 处理
-
XHR : 使用
XMLHttpRequest
时,处理 JSON 数据需要手动解析。javascriptconst data = JSON.parse(xhr.responseText);
-
Fetch :
fetch
提供了response.json()
方法,直接解析 JSON 数据,简化了代码。javascriptfetch('https://api.example.com/data') .then(response => response.json()) .then(data => console.log(data));
5. 默认行为更直观
-
XHR : 默认情况下,
XMLHttpRequest
是异步的,但你必须显式地处理许多常见情况,比如跨域请求、超时等。 -
Fetch :
fetch
的默认行为更符合现代 Web 开发需求,如遵循 CORS 标准、默认不发送 cookies 等。你可以通过选项轻松配置这些行为。
6. 更好的错误处理
-
XHR :
XMLHttpRequest
只有在网络错误或请求被阻止时会触发onerror
,但它无法区分不同类型的错误,也无法轻松处理 HTTP 状态码。 -
Fetch :
fetch
通过Promise
进行错误处理,允许你更细粒度地控制请求的成功与失败。你可以轻松检查 HTTP 状态码并作出相应处理。javascriptfetch('https://api.example.com/data') .then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .catch(error => console.error('Fetch error:', error));
总结
fetch
通过更简洁的 API、原生的 Promise
支持、内置的 JSON 处理、更好的流媒体支持,以及更直观的默认行为,解决了 XMLHttpRequest
在使用上的诸多不便,适合现代 JavaScript 开发需求。
fetch() 方法的两个参数
fetch()方法接收两个参数:第一个参数表示要获取的资源路径;第二个参数表示请求的配置项(可选)
js
fetch('https://127.0.0.1/api/articles/1/3').then(function(res){
if(res.ok) {
return res.json();
}
})
// 定义第二个参数
fetch('https://127.0.0.1/api/articles/1/3', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
token:'token'
},
cache: 'default',
mode: 'cors',
}).then(function(res){
if(res.ok) {
return res.json();
}
})
设置请求的头信息
在POST提交的过程中,一般是表单提交,可是,经过查询,发现默认的提交方式是:
Content-Type:text/plain;charset=UTF-8
,这个显然是不合理的,改为 application/x-www-form-urlencoded
js
fetch('https://www.baidu.com/search/error.html', {
method: 'POST',
headers: new Headers({
'Content-Type': 'application/x-www-form-urlencoded' // 指定提交方式为表单提交
}),
body: new URLSearchParams([["foo", 1],["bar", 2]]).toString()
})
.then((res)=>{
return res.text()
})
.then((res)=>{
console.log(res)
})
默认不使用 cookie
默认情况下, fetch 不会从服务端发送或接收任何 cookies,要发送 cookies,必须设置 credentials 选项
js
fetch('http://127.0.0.1/search/name', {
method: 'GET',
credentials: 'include' // 强制加入凭据头
})
.then((res)=>{
return res.text()
})
GET请求及传参
GET请求中如果需要传递参数怎么办?
这个时候,只能把参数写在URL上来进行传递了。
js
fetch('http://127.0.0.1/search?a=1&b=2', { // 在URL中写上传递的参数
method: 'GET'
})
.then((res)=>{
return res.text()
})
POST 请求及传参
POST请求的参数,放在第二个参数的body属性中
js
fetch('http://127.0.0.1/searchs', {
method: 'POST',
body: new URLSearchParams([["foo", 1],["bar", 2]]).toString() // 这里是请求对象
})
.then((res)=>{
return res.text()
})
POST提交改为application/x-www-form-urlencoded
js
fetch('http://127.0.0.1/searchs', {
method: 'POST',
headers: new Headers({
'Content-Type': 'application/x-www-form-urlencoded' // 指定提交方式为表单提交
}),
body: new URLSearchParams([["foo", 1],["bar", 2]]).toString() // 这里是请求对象
})
.then((res)=>{
return res.text()
})
fetch 的使用场景,有哪些优缺点?
使用场景
fetch
API 在以下场景中非常适用:
-
简单的 HTTP 请求:
- 当需要向服务器发送简单的
GET
、POST
、PUT
、DELETE
请求时,fetch
是非常适合的选择。它简洁的语法使得处理这些请求变得直观。
- 当需要向服务器发送简单的
-
处理 JSON 数据:
fetch
内置了response.json()
方法,特别适合从 API 获取 JSON 数据,并将其解析为 JavaScript 对象。
-
支持异步编程:
- 由于
fetch
基于Promise
,它适用于所有需要异步操作的场景,特别是在需要链式处理多个异步操作时,如连续的 API 请求。
- 由于
-
流媒体或大文件处理:
fetch
可以用于处理流媒体响应或大文件下载,通过ReadableStream
逐块处理数据而不是一次性加载全部内容,减少内存占用。
-
跨域请求:
fetch
默认遵循 CORS (Cross-Origin Resource Sharing) 规范,使其在处理跨域请求时更加安全和方便。
-
与现代浏览器兼容:
fetch
在现代浏览器中得到广泛支持,对于不需要支持老旧浏览器的应用,fetch
是一个理想选择。
优点
-
简洁和现代化:
fetch
的 API 设计简洁,代码更易读、维护性更高,符合现代 JavaScript 开发习惯。
-
Promise-based:
fetch
使用Promise
,支持async
/await
,更容易处理异步代码,避免了回调地狱。
-
更好的错误处理:
- 可以通过
then
和catch
来细粒度地处理请求结果和错误。
- 可以通过
-
流式处理:
- 支持
ReadableStream
,适合处理流媒体和大文件,能够逐步读取数据。
- 支持
-
灵活的配置:
fetch
允许通过选项灵活配置请求方法、头信息、请求体、缓存行为、跨域策略等,满足不同的需求。
-
内置 JSON 支持:
- 提供了
response.json()
等方法,简化了从服务器获取 JSON 数据并解析的流程。
- 提供了
缺点
-
不支持进度监听:
fetch
不支持上传或下载的进度监听,这在处理大文件上传或下载时可能不够理想。如果需要进度反馈,可能需要回到XMLHttpRequest
或使用第三方库。
-
没有内置超时处理:
fetch
没有直接支持请求超时,开发者需要手动实现超时逻辑。这对于处理可能耗时过长的请求时增加了代码复杂性。
-
不自动抛出 HTTP 错误:
- 当服务器返回 4xx 或 5xx 状态码时,
fetch
不会自动抛出错误,开发者需要手动检查response.ok
属性并抛出错误。这与很多开发者的预期不同。
- 当服务器返回 4xx 或 5xx 状态码时,
-
浏览器兼容性问题:
- 尽管大多数现代浏览器都支持
fetch
,但是在较旧的浏览器(如 IE)中不支持,需要使用 polyfill 来保证兼容性。
- 尽管大多数现代浏览器都支持
-
跨域请求中的复杂性:
- 在处理跨域请求时,
fetch
严格遵循 CORS 规范,有时会导致与服务器的交互变得复杂。如果后端没有正确配置 CORS,会导致请求失败。
- 在处理跨域请求时,
总结
fetch
是一个功能强大且现代化的 API,适用于大多数网络请求场景。
它的简洁性和与现代异步编程模式的兼容性使其在新项目中非常受欢迎。
然而,对于某些高级需求,如进度监听或老旧浏览器支持,可能仍需考虑使用 XMLHttpRequest
或第三方库。