react-fetch详谈

本文介绍fetch在React中的应用,包括其相对于XMLHttpRequest的优势、如何在React项目中使用fetch获取及发送数据、解决跨域问题的方法及fetch异常处理技巧。

React-Fetch

引言: 

       fetch在React-js中相当于XMLHttpRequest,它提供了许多与XMLHttpRequest相同的功能,但被设计成更具可拓展性和高效性。XMLHttpRequest在发送web请求时需要开发者配置相关请求信息和成功后的回调,尽管开发者只关心成功后的业务处理,但是也要配置繁琐的内容,导致配置和调用比较混乱,也不符合关注分离的原则,fetch的出现正是为了解决XMLHttpRequest出现的这些问题。

        使用fetch的理由参见传统Ajax已死,Fetch永生

        fetch是基于promise设计的,有三大优点:

         1. 语法简单,更加语义化

         2. 基于标准的promise实现,支持async/await

         3. 使用ismorphic-fetch,方便同构


常见问题:

fetch兼容性

       fetch在各个浏览器低版本的情况下是不被支持的,由于fetch是基于promise实现的,所以在低版本浏览器中promise未必被原生支持。所以,二者都需要polyfill来解决问题:

       promise:es6-promise,babel-promise

       fetch:whatwg-fetch,ismorphic-fetch(同构)

fetch默认不携带cookie

       fetch不管在同域还是在跨域的情况下,默认都不携带cookie的,所以那些需要权限验证的请求就无法正常获取到数据,这时候需要配置credentials项,有一下三个选项可添:

      omit: 默认值,忽略cookie的发送

      same-origin: 表示cookie只能同域发送,不能跨域发送

      include: 表示既可以同域发送,也可以跨域发送

fetch请求对某些错误的http状态不会reject

      这主要是fetch返回promise导致的,因为fetch返回的promise在某些错误的http状态下如400、500不会reject,相反它会被resolve(但是resolve的ok返回值为false),所以一般会对fetch请求做一层封装:

function checkStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    return response;
  }
  const error = new Error(response.statusText);
  error.response = response;
  throw error;
}
function parseJSON(response) {
  return response.json();
}
export default function request(url, options) {
  let opt = options||{};
  return fetch(url, {credentials: 'include', ...opt})
    .then(checkStatus)
    .then(parseJSON)
    .then((data) => ( data ))
    .catch((err) => ( err ));
}

fetch跨域问题

       可以对fetch的mode项进行配置,有一下三个选项:

       same-origin:该模式是不允许跨域的,它需要遵循同源策略,否则浏览器会返回一个error告知

                           不能跨域,其对应的response type 为basic

        cors: 该模式支持跨域请求,顾名思义,它是以cors形式跨域,当然该模式也可以在同域请求

                  下不需要后端额外的cors支持,其对应的response type 为cors

        no-cors: 该模式用于跨域请求但是服务器不带cors响应头,也就是服务器不支持cors,这也

                        是fetch特殊的请求跨域方式,其对应的response type 为opaque

        针对跨域请求,cors跨域是常见的跨域请求实现。


fetch实现步骤
1. 导入  
   install :  npm install whatwg-fetch 
    引入:    import React, { Component }  from 'react'
                 import 'whatwg-fetch'

2.  fetch获取数据                      

fetch('https://api.github.com/users/chriscoyier/repos')
  .then(response => {/* do something */})

     fetch是基于promise的,所以在response的箭头函数内部可以做自己想做的事情。

     有三种方式解析获取到的数据:

     1  json数据       用reponse.json()来解析

     2 xml格式文件  用response.text()来解析

     3 图片文件       用response.blob()来解析

返回的response通常有一下几部分组成:

{
  body: ReadableStream
  bodyUsed: false
  headers: Headers
  ok : true
  redirected : false
  status : 200 statusText : "OK" type : "cors" url : "http://some-website.com/some-url" __proto__ : Response }

response每次响应后,只有ok,status,statusText是不同的,以上status:200,statusText:'OK',证明获取成功。


3.  发送数据

    使用fetch发送数据,只需要配置三个参数: 

     fetch('some-url', option)

     第一个参数是设置请求方法,如post、get或者del,fetch会自动设置为get

     第二个参数是设计头部,一般使用json数据格式,所以一般设置contentType为application/json

     第三个参数是json内容的主体,因为json内容是必须的,所以调用时会使用JSON.stringify

实践中post请求会像下面这样

let content = {some: 'content'};
// The actual fetch request
fetch('some-url', {
  method: 'post',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(content)
})
// .then()...


fetch异常处理

虽然ajax响应成功,但是仍然会有问题出现:

1 可能获取不存在的资源

2 没有权限获取资源

3 输入参数有误

4 服务器抛出异常

5 服务器超时

6 服务器崩溃

7 API更改

8 ......

最普遍的方法就是catch 

fetch('https://api.github.com/users/chrissycoyier/repos')
  .then(response => response.json())
  .then(data => console.log('data is', data))
  .catch(error => console.log('error is', error));

详情参见使用fetch


处理其他响应类型

fetch('some-url')
  .then(handleResponse)
  .then(data => console.log(data))
  .then(error => console.log(error))

function handleResponse (response) {
  let contentType = response.headers.get('content-type')
  if (contentType.includes('application/json')) {
    return handleJSONResponse(response)
  } else if (contentType.includes('text/html')) {
    return handleTextResponse(response)
  } else {
    // Other response types as necessary. I haven't found a need for them yet though.
    throw new Error(`Sorry, content-type ${contentType} not supported`)
  }
}

function handleJSONResponse (response) {
  return response.json()
    .then(json => {
      if (response.ok) {
        return json
      } else {
        return Promise.reject(Object.assign({}, json, {
          status: response.status,
          statusText: response.statusText
        }))
      }
    })
}
function handleTextResponse (response) {
  return response.text()
    .then(text => {
      if (response.ok) {
        return json
      } else {
        return Promise.reject({
          status: response.status,
          statusText: response.statusText,
          err: text
        })
      }
    })
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值