Fetch API

本章视频讲解在这里,连续看6个视频

Fetch API 提供了一个用于获取资源(目前主要是网络资源)的接口。

比用 XMLHttpRequest 更强大、更灵活。

fetch 构建请求消息

url 和 method

调用浏览器内置的 fetch 函数,就可以 发送http请求,

第1个参数 resource 通常就是 url字符串

第2个参数 options 是一个可选参数,用来设置请求行为的

比如


fetch('/api/something'); // 缺省的 HTTP Method 是 GET

fetch(
  "/api/something",
  { 
    method: 'POST',
    body : 'postdata.....'
  }
);

url 参数

url query String 参数 就是 urlencode 格式

自己写代码拼接出 urlencode 格式的字符串比较麻烦,


可以使用浏览器内置的 URLSearchParams 类型。

URLSearchParams对象的方法 toString ,可以将对象序列化为 urlencoded 格式

比如:

var queryStr = new URLSearchParams({code:'6000001', time:'2022-02-23' }).toString()

fetch(`http://localhost/api/stock?${queryStr}`)

消息头

fetch 发送http请求要定制一些消息头,可以通过 options 参数里面的 headers 属性设置,如下

fetch(  
  '/api/something',
  {  
    headers: {
      username: "byhy", 
      password: "abcdefgh",
      "Content-Type": "application/json"
    }
  }
)

消息体

fetch 的请求消息体都是参数对象 optionsbody 属性中设置的

如果有消息体,我们应该在 options 里面的 headers 中,用 Content-Type 指明消息体格式

如果没有指明,缺省为 text/plain;charset=UTF-8

urlencode 格式

消息体也可以是 urlencode 格式,同样可以使用 URLSearchParams


其实,如果使用jQuery发送请求, data参数如果是js 对象,缺省行为就是转化为 urlencode格式

所以可以直接传对象,如下

var username = 'byhy'
var password = '88888888'

var payload = new URLSearchParams(
  { username: username, password:password}).toString()

fetch(  
  '/api/mgr/signin',
  {      
    method: 'POST',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body: payload
  }
)

当然,如果你觉得直接构建 urlencode格式的字符串不麻烦也可以直接构建,比如

var username = 'byhy'
var password = '88888888'

fetch(  
  '/api/mgr/signin',
  {      
    method: 'POST',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body: `username=${username}&password=${password}`
  }
)

JSON 格式

现在的API接口消息体 很多是JSON格式的字符串。

可以使用浏览器js内置对象 JSON

JSON 的方法 stringify 可以序列化js对象为JSON格式

fetch(  
  '/api/mgr/signin',
  {  
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({ username: 'byhy', password:'88888888' })
  }
)

fetch 解析响应消息

fetch调用后,返回值是一个Promise对象。

如果成功获取服务端响应消息,这个Promise对象就会 resolve 一个 Response 对象

对这个Response对象的处理,自然应该在 Promise对象的then方法中

可以调用 Response对象的属性和方法获取响应消息中的数据

比如,

响应状态码

通过 Response对象的 status 属性获取响应状态码

fetch(  
  '/api/mgr/signin',
  {      
    method: 'POST',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body: `username=byhy&password=88888888`
  }
)
.then(response => {
  console.log(response.status)
})

响应消息头

通过 Response对象的 headers 属性获取响应消息头

该属性返回的是一个 Headers 类型的对象

可以通过 它的

  • entries() 方法遍历获取所有的消息头

  • get() 方法获取某个消息头

比如

fetch(  
  '/api/mgr/signin',
  {      
    method: 'POST',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body: `username=byhy&password=88888888`
  }
)
.then(response => {
  let headers = response.headers

  // 遍历获取所有的消息头
  for (const pair of headers.entries()) {
   console.log(`${pair[0]}: ${pair[1]}`);
  }
  
  // 获取某个消息头
  let ct = headers.get('content-type')
  console.log(`content-type 为 ${ct}`);
})

响应消息体

HTTP响应消息体内容,通常是通过 Resonse对象的方法,比如 json()、text() 等方法获取

因为响应消息体可能会分批从网络发送回来,所以这些方法往往不是立即返回数据,而是返回一个Promise

响应消息体数据全部读取完毕后,再resolve这个Promise对象

json 格式

比如对json格式的响应消息体, 可以这样写

fetch(  
  '/api/mgr/signin',
  {      
    method: 'POST',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body: `username=byhy&password=88888888`
  }
)
.then(response => {
  return response.json()
})
.then(data => {
  console.log(data)
})

可以简写为

fetch(  
  '/api/mgr/signin',
  {      
    method: 'POST',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body: `username=byhy&password=88888888`
  }
)
.then(response => response.json())
.then(data => console.log(data))

通常,会在最后加上错误处理

如下:

fetch(
  '/api/mgr/signin3',
  {      
    method: 'POST',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body: `username=byhy&password=88888888`
  }
)
.then(response => response.json())
.then(data => console.log(data))
.catch(reason =>{console.log('登录认证出现错误:',reason)});

其它响应格式

如果返回的响应消息不是json格式,而是其它文本格式,比如XML

可以通过 text()方法,得到消息体原始字符串, 再自行进行后续的转化

注意:text()方法 返回的也是promise对象

可以这样处理:

fetch(  
  '/api/mgr/signin',
  {      
    method: 'POST',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body: `username=byhy&password=88888888`
  }
)
.then(response => response.text())
.then(data => {
  console.log('响应原始文本内容为:',data)
  // 后面可以自己写代码对data进行处理
})

async/await

针对promise,更推荐的是 使用 async/await 语法糖

比如

var response = await fetch(
  '/api/mgr/signin',
  {      
    method: 'POST',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body: `username=byhy&password=88888888`
  }
)

var resObj = await response.json()
console.log('登录返回结果',resObj)

为什么 response.json() 前面也要加个 await 呢?

因为 response.json() 返回的也是promise , 所以要await


使用 async/await 更方便的是再接收到响应后,继续后续的消息发送和接收

比如

// 先登录
var response = await fetch(
  '/api/mgr/signin',
  {      
    method: 'POST',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body: `username=byhy&password=88888888`
  }
)
var resObj = await response.json()
console.log('登录返回结果',resObj)

// 再获取客户数据
if (resObj.ret === 0){
  response = await fetch(
    '/api/mgr/customers?action=list_customer&pagenum=1&pagesize=5')  
  resObj = await response.json();
  console.log('获取客户数据结果',resObj)  
}


fetch返回的promise 或者 response.json() 返回的promise,

如果其中任意一个失败了,对应的 await 会抛出 reject的结果对象,从而中断后续的代码执行。

可以通过 try… catch 捕获处理

比如

try{
  // 先登录
  var response = await fetch(
    '/api/mgr/signin33',
    {      
      method: 'POST',
      headers: {'Content-Type': 'application/x-www-form-urlencoded'},
      body: `username=byhy&password=88888888`
    }
  )
  var resObj = await response.json() // 此处会抛异常
  console.log('登录返回结果',resObj)

  // 再获取客户数据
  if (resObj.ret === 0){
    response = await fetch(
      '/api/mgr/customers?action=list_customer&pagenum=1&pagesize=5')  
    resObj = await response.json();
    console.log('获取客户数据结果',resObj)  
  }
} 
catch (error) {
  console.log('捕获到错误', error)
  // 下面写错误处理的代码
}