持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情
详解 H5 新增的 Fetch API
1.Fetch API 出现的原因
在过去我们通常是使用XMLHttpRequest
对象与服务器交互,从而实现 AJAX 异步请求,但XMLHttpRequest
存在以下问题:
- 所有的功能全部集中在同一个对象上,容易书写出混乱且不易维护的代码
- 采用传统的事件驱动模式,无法适配 ES6 提出的
Promise
为了解决以上问题,官方就提出了新 API-Fetch
,它主要有以下特点:
- 并非取代 AJAX,而是对 AJAX 传统 API 的改进
- 精细的功能分割:头部信息、请求信息、响应信息等均分布到不同的对象,更利于处理各种复杂的 AJAX 场景
- 使用 Promise API,更利于异步代码的书写
- Fetch API 并非 ES6 的内容,属于 HTML5 新增的 Web API
- 需要掌握网络通信的知识
2.基本使用
使用 fetch
函数即可立即向服务器发送网络请求
const url = "请求地址";
fetch(url); //已发送请求,返回一个Promise对象
/*fetch(url,{
//请求参数对象
method: 'POST',
})*/
2.1 参数
该函数有两个参数:
- 必填,字符串,请求地址
- 选填,对象,请求配置
请求配置对象的可选参数:
-
method:字符串,请求方法,默认值 GET
-
headers:对象,请求包含的 Headers 对象,详细介绍见第五章
-
body: 请求体的内容,必须匹配请求头中的 Content-Type
-
mode:字符串,请求模式,能解决跨域问题
- cors:默认值,配置为该值,会在请求头中加入 origin 和 referer
- no-cors:配置为该值,不会在请求头中加入 origin 和 referer,跨域的时候可能会出现问题
- same-origin:指示请求必须在同一个域中发生,如果请求其他域,则会报错
-
credentials: 如何携带凭据(cookie)
- omit:默认值,不携带 cookie
- same-origin:请求同源地址时携带 cookie
- include:请求任何地址都携带 cookie
-
cache:配置缓存模式
- default: 表示 fetch 请求之前将检查下 http 的缓存。
- no-store: 表示 fetch 请求将完全忽略 http 缓存的存在。这意味着请求之前将不再检查下 http 的缓存, 拿到响应后, 它也不会更新 http 缓存。
- no-cache: 如果存在缓存, 那么 fetch 将发送一个条件查询 request 和一个正常的 request, 拿到响应后, 它会更新 http 缓存。
- reload: 表示 fetch 请求之前将忽略 http 缓存的存在, 但是请求拿到响应后, 它将主动更新 http 缓存。
- force-cache: 表示 fetch 请求不顾一切的依赖缓存, 即使缓存过期了, 它依然从缓存中读取。 除非没有任何缓存, 那么它将发送一个正常的 request。
- only-if-cached: 表示 fetch 请求不顾一切的依赖缓存, 即使缓存过期了, 它依然从缓存中读取。 如果没有缓存, 它将抛出网络错误(该设置只在 mode 为”same-origin”时有效)。
重点是前三个属性 —— method、headers、body 的配置,是我们平时开发经常需要配置的属性。
2.2 返回值
fetch 函数返回一个 Promise 对象
- 当收到服务器的返回结果(与响应状态码无关)后,Promise 进入 resolved 状态,状态数据为 Response 对象
- 当网络发生错误(或其他导致无法完成交互的错误)时,Promise 进入 rejected 状态,状态数据为错误信息
3.Request 对象
除了使用基本的 fetch 方法,还可以通过创建一个 Request 对象来完成请求(实际上,fetch 的内部会帮你创建一个 Request 对象)
如以下代码:
const myRequest = new Request(url地址, 请求配置对象); //先创建一个 Request 对象
const resp = await fetch(myRequest); //fetch发送请求 resp为一个 Response 对象
Request 对象的参数与 fetch 函数的参数一致,使用详细介绍见第一章 fetch 方法参数介绍。
注意点:
尽量保证每次请求都是一个新的 Request 对象(post 请求上传大型文件时导致重复上传失败),此时应需调用 Request 对象clone
方法赋值一个全新的 Request 对象,新对象配置与之前的一致。
4.Response 对象
一般并不会手动创建 Response 对象,只有测试时才会创建 Response 对象,因为当 fetch 方法返回的 Promise 进入 resolved 状态,返回的数据就是 Response 对象。
//const myResponse = new Response(响应体数据, 响应配置对象);
const resp = new Response(
`[
{"id":1, "name":"北京"},
{"id":2, "name":"天津"}
]`,
{
ok: true,
status: 200,
}
);
4.1 Response 对象的主要属性
- body:响应体,用于存放响应数据,实现为 ReadableStream
- bodyUsed: boolean,表示响应体内容是否已被读取
- headers: 响应包含的 Headers 对象
- ok:boolean,表示 HTTP 状态码的含义,200~299 的状态码返回 true,其他状态码返回 false redirected: boolean,表示响应是否至少经过一次重定向
- status:number,表示响应的 HTTP 状态码,默认为 200
- statusText: string,包含对 HTTP 状态码的正式描述
- type: string,包含响应类型。
- basic:表示标准的同源响应
- cors:表示标准的跨源响应
- error:表示响应对象是通过 Response.error()创建的
- opaque:表示 no-cors 的 fetch()返回的跨源响应
- opaqueredirect:表示对 redirect 设置为 manual 的请求的响应
- url: 包含响应 URL 的字符串。对于重定向响应,这是最终的 URL,非重定向响应就是它产生的
4.2 Response 对象的主要方法
- text():用于处理文本格式的 Ajax 响应。它从响应中获取文本流,将其读完,然后返回一个被解决为 string 对象的 Promise 对象。
- blob():用于处理二进制文件格式(比如图片或者电子表格)的 Ajax 响应。它读取文件的原始数据,一旦读取完整个文件,就返回一个被解决为 blob 对象的Promise 对象。
- json():用于处理 JSON 格式的 Ajax 的响应。它将 JSON 数据流转换为一个被解决为 JavaScript 对象的Promise 对象。
- redirect():可以用于重定向到另一个 URL。它会创建一个新的 Promise,以解决来自重定向的 URL 的响应。
- error():用于产生表示网络错误的 Response 对象(网络错误会导致 fetch()返回的 Promise 对象被拒绝)。
- clone():用于会创建一个一模一样的副本,不会覆盖任何值,在响应体被读取之后再克隆会导致抛出 TypeError。(有响应体的 Response 对象只能读取一次)
5.Headers 对象
在 Request 和 Response 对象内部,会将传递的请求头对象,转换为 Headers 对象
使用方法:
const myHeaders = new Headers({
a: 1,
b: 2,
}); // 创建一个 Headers 对象
const myRequest = new Request(url地址, {
headers,
});
const resp = await fetch(myRequest); // resp为一个 Response 对象
5.1 Headers 对象的主要属性
- Accept:浏览器可以处理的内容类型。
- Accept-Charset:浏览器可以显示的字符集。
- Accept-Encoding:浏览器可以处理的压缩编码类型。
- Accept-Language:浏览器使用的语言。
- Connection:浏览器与服务器的连接类型,如:
keep-alive
表示长连接 - Cookie:页面中设置的 Cookie。
- Host:发送请求的页面所在的域。
- Referer:发送请求的页面的 URI。由于该字段在 HTTP 规范中就拼错了,所以将错就错。(正确的拼写应是 Referrer。)
- User-Agent:浏览器的用户代理字符串。
5.2 Headers 对象的主要方法
- has(key):检查请求头中是否存在指定的 key 值
- get(key): 得到请求头中对应的 key 值
- set(key, value):修改对应的键值对
- append(key, value):添加对应的键值对
- keys(): 得到所有的请求头键的集合,可通过 for-of 遍历
- values(): 得到所有的请求头中的值的集合,可通过 for-of 遍历
- entries(): 得到所有请求头中的键值对的集合,可通过 for-of 遍历
6.fetch API 实现文件上传
通过 fetch API 使用 AJAX 技术进行无刷新文件上传。
上传流程:
- 客户端将文件数据发送给服务器
- 服务器保存上传的文件数据到服务器端
- 服务器响应给客户端一个文件访问地址
请求方法:POST(因为文件数据量较大) 请求的表单格式:multipart/form-data 请求体中必须包含一个键值对,键的名称是服务器要求的名称,值是文件数据
HTML5 中,JS 仍然无法随意的获取文件数据,但是可以获取到 input 元素中,被用户选中的文件数据 可以利用 HTML5 提供的 FormData 构造函数来创建请求体
如上传图片:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<img src="" alt="" id="imgAvatar" />
<input type="file" id="avatar" />
<button>上传</button>
<script>
async function upload() {
const inp = document.getElementById('avatar');
if (inp.files.length === 0) {
alert('请选择要上传的文件');
return;
}
const formData = new FormData(); //构建请求体
formData.append('imagefile', inp.files[0]);//键名为服务器所规定的键名
const url = '服务器地址';//请求地址
const resp = await fetch(url, {
method: 'POST',
body: formData, //自动修改请求头
});
const result = await resp.json();
return result;
}
document.querySelector('button').onclick = async function () {
const result = await upload();
const img = document.getElementById('imgAvatar');
img.src = result.path;
};
</script>
</body>
</html>
结语
这是我目前所了解的知识面中最好的解答,当然也有可能存在一定的误区。
所以如果对本文存在疑惑,可以在评论区留言,我会及时回复的,欢迎大家指出文中的错误观点。
最后码字不易,觉得有帮助的朋友点赞、收藏、关注走一波。