# fetch 介绍

​ fetch () 是一个全局方法,提供一种简单,合理的方式跨网络获取资源。它的请求是基于 Promise。

# fetch 使用语法

fetch(url,options).then((response)=>{
	// 处理 http 响应
},(error)=>{
	// 处理错误
})
  • url:是发送网络请求的地址
  • options:发送请求参数
    • body: http 请求参数
    • mode: 指定请求模式。
      • 默认值为 cros: 允许跨域;
      • same-origin: 只允许同源请求;
      • no-cros: 只限于 get、post 和 head,并且只能使用有限的几个简单标头。
    • cache: 用户指定缓存
    • method:请求方法,默认 GET
    • signal:用于取消 fetch
    • header:http 请求头设置
    • keepalive:用于页面卸载时,告诉浏览器后台保持连接,继续发送数据
    • credentials:cookie 设置
      • 默认 omit,忽略不带 cookie,
      • same-origin 同源请求带 cookie
      • inclue 无论跨域还是同源都会带 cookie

# response 对象

​ fetch 请求成功后,响应 response 对象:

  • status:http 状态码,范围在 100-599 之间
  • statusText:服务器返回状态文字描述
  • ok:返回布尔值,如果状态码 2 开头的,则返回 true,反之 false
  • headers:响应头
  • body:响应体
  • type:返回请求类型
  • redirected:返回布尔值,表示是否发生过跳转

# 读取内容方法

response 对象根据服务器返回的不同类型数据,提供了不同的读取方法。分别有:

  • response.text ():得到文本字符串
  • response.json ():得到 json 对象
  • respnse.blob ():得到二进制 blob 对象
  • response.formData ():得到 fromData 表单对象
  • response.arrayBuffer ():得到二进制 arrayBuffer 对象

# response.clone()

stream 对象只能读取一次,读取完就没了,这意味着,上边的五种读取方法,只能使用一个,否则会报错。因此 response 对象提供了 clone () 方法,创建 rsponse 对象副本,实现多次读取。如:将一张图片,读取两次:

const response1 = await fetch('flowers.jpg');
const response2 = response1.clone();
const myBlob1 = await response1.blob();
const myBlob2 = await response2.blob();
image1.src = URL.createObjectURL(myBlob1);
image2.src = URL.createObjectURL(myBlob2);

# response.body()

body 属性返回一个 ReadableStream 对象,供用户操作,可以用来分块读取内容,显示下载的进度就是其中一种应用

const response = await fetch('flower.jpg');
const reader = response.body.getReader();
while(true) {
  const {done, value} = await reader.read();
  if (done) {
    break;
  }
  console.log(`Received ${value.length} bytes`)
}

response.body.getReader() 返回一个遍历器,这个遍历器 read () 方法每次都会返回一个对象,表示本次读取的内容块

# 不同请求如何处理

请求方式不同,传值方式也不同。xhr 会分别处理 get 和 post 数据传输,还有请求头设置,同样 fetch 也需要分别处理。

# get 方式:

只需要在 url 中加入传输数据,options 中加入请求方式

<input type="text" id="user"><br>
<input type="password" id="pas"><br>
<button onclick="login()">提交</button>
<script>
 function login(){
  fetch(`http://localhost:80/fetch.html?user=${user.value}&pas=${pas.value}`, {
   method:'GET'
  }).then(response=>{
   console.log('响应',response)
  })
 }
</script>

# post 方式:

使用 post 发送请求时,需要设置请求头、请求数据等

fetch(`http://localhost:80/ES6练习题/53fetch.html`, {
 method:'POST',
 headers:{
  'Content-Type':'application/x-www-form-urlencoded;charset=UTF-8'
 },
 body:`user=${user.value}&pas=${pas.value}`
 }).then(response=>{
  console.log('响应',response)
})

如果是提交 json 数据时,需要把 json 转换成字符串:

body: JSON.stringify(json)

如果提交的是表单数据,使用 formData 转化:

body: new FormData(form)

上传文件,可以包含在整个表单里一起提交:

const input = document.querySelector('input[type="file"]');
const data = new FormData();
data.append('file', input.files[0]);
data.append('user', 'foo');
fetch('/avatars', {
  method: 'POST',
  body: data
});

上传二进制数据,将 blob 或 arrayBuffer 数据放到 body 属性里:

let blob = await new Promise(resolve =>
  canvasElem.toBlob(resolve,  'image/png')
);
let response = await fetch('/article/fetch/post/image', {
  method:  'POST',
  body: blob
});

# fetch 常见坑:

  1. 兼容性不好
  2. 默认不带 cookie,传 cookie 时,必须在 header 参数内加上 credenials:'include' ,才会像 xhr 将 cookie 带请求头中
  3. 异常处理需要手动实现