重新认识FetchAPI接口

847 阅读3分钟

FetchAPI 并不仅仅是一个用来发网络请求的fetch方法,它提供了Request 和 Response (以及其他与网络请求有关的)对象的通用定义,这些定义取代了之前一的些比较分散的定义方式,一言以蔽之,web请求逐步规范起来了。

关于FetchAPI的一个简单的用例:

fetch(`url`,{
    method:'post',
    headers:{},
    body:JSON.stringify({
      name:'Andy'
    })
}).then(response => {
    return response.json()
}).then(res => {
    console.log('结果在这里--->',res)
})

上面的代码只是处理了服务端返回JSON数据的情况,并没有考虑其他类型的响应数据:如果服务端返回了一个文件,上述代码就会出错:Uncaught SyntaxError: Unexpected end of JSON input

我本人对FetchAPI了解和使用很少,类似上述的一个报错引起了我的注意,于是抽空查了资料,才意识到它的革命性意义:规范web请求

FetchAPI让网路请求更规范

首先,FetchAPI在语言层面定义了几个主要接口:

  • Request表示一次网络请求
  • Response表现了一次网络请求的数据
  • Headers定义了请求头和响应头的一系列操作

可以将一次网络请求用下面的过程表示:

//创建请求request
//1.构造请求头
const headers = new Headers()
headers.append('content-type','application/json')

//2.构造request
const request = new Request('url',{
    method:'get',
    mode:'cors',//表示一次跨资源共享的请求
    headers:headers,
    //...
})
//发送
fetch(request).then(response => {
  if(response.ok){
    //一次ok的响应:200
  }else{
    //其他的响应: 4xx, 5xx
  }
  const contentType = response.headers.get('content-type')
  //根据内容类型调用不同的方法 .blob(), .text(), .formData()
  if(contentType === 'application/json'){
      return response.json()
  }else{
      //...
  }
},err=>{
  //没有收到响应
  /*
  1. 网络故障导致发送失败
  2. 超时
  */
}).then(res => {
    console.log('结果在这里--->',res)
})

上面我们通过构造函数明确了请求相关的模块:

  • request
  • headers
  • response 然后Response接口提供了ok布尔属性方便判定响应的有效性。此外,可以指定请求的模式是跨域请求还是同源请求(mode),指定是否携带凭证(credentials),一切都变得可配置,相比XMLHttpRequest里的处理方式优雅了不知多少。

另外,我们还可以构造自定义的response:const res = new Response()

上述所有用到的API都属于FetchAPI

如何处理重定向

众所周知,Ajax里是没有重定向的概念的,因为它属于文档的布局异步更新,无法像传统的response那样直接把页面重定到某个路径。

前端要想在Ajax里引入重定向,只能通过服务端返回一些约定的数据(一般放到HttpHeader里作为标记),js读取header进行客户端内页面导航。

FetchAPI里考虑了这一点,将之规范化:

//服务端
...
//一个API接口的controller片段
res.status(302).redirect('/love')
...

//客户端
fetch(request).then(response => {
  //response.redirected 表示该响应是否是重定向的
  const isRedirected = response.redirected
  const redirectedUrl = response.url
  //客户端判定是否跳转
})

这里我们无需前后端的任何额外数据约定,规范简洁了很多,不是吗?

如何处理超时问题

这里需要指出的是FetchAPI没有提供timeout的定义,而是把控制权交给开发,虽减少了一些便利,但长远来看是提升了接口的健壮性。

我们可以通过AbortController接口来处理fetch请求的超时

const abortController = new AbortController()
//10秒钟后终止关联的请求(超时间隔为10s)
setTimeout(()=>{
     abortController.abort()
 },10000)
fetch('/api/login', {
    method: 'get',
    signal:abortController.signal
}).then(res => {
},err=>{
  console.log(`这里可以捕获到超时错误-->`,err)
})

总结

FetchAPI本质上把之前Ajax上的一些零散的方式归纳、总结、拆分、提炼为一个个的独立模块,这些模块相辅相成,组合在一起支撑了web请求的架构。而每个模块又提供了很多便捷的操作方法。

如果你还没怎么用过FetchAPI,建议你试试.