fetch封装

import CONSTANT from './CONSTANT'
import {
      Toast } from 'antd-mobile'
import {
     getAppLogin, isNetworkConnected, showNoNetPage} from '../utils/getAppApi'
import {
      history } from '../utils/history'
import * as Sentry from '@sentry/browser'
import {
     redirectSSO} from "../utils/Utility"

window.requestDict = window.requestDict || {
     }
let status200 = false

// 发送请求时的loading及最小高度的处理
const Loading = (flag, loadingClass) => {
     
  if (loadingClass && document.getElementsByClassName(loadingClass)[0]) {
     
    const elm = document.getElementsByClassName(loadingClass)[0]
    if (flag && !elm.className.includes('loading_md')) {
     
      elm.className += ' loading_md '
    } else {
     
      elm.className = elm.className.replace('loading_md', '')
    }
  }
}

// 会话过期需清除的数据
const clear401Data = () => {
     
  const clearData = ['userInfo', 'wechatFree', 'token']
  clearData.forEach(data => localStorage.removeItem(data))
}

// 发送请求时的处理
const handleRequest = (config) => {
     
  Loading(true, config.loadingClass)
  return config
}

// 服务端返回的响应头处理
const handleResponseHeader = (headers, rep, statusCode) => {
     
  if (window.isApp) {
     
    return rep
  }
  if (!headers) {
     
    clear401Data()
  }

  if (rep.status == 200) {
     
    status200 = true
    return rep
  } else if (rep.status >= 500) {
     
    Sentry.setExtra('fetch_data', rep)
    Sentry.captureMessage('fetch_500_error')
    if(!statusCode) history.push('/serverError')
  } else if (rep.status == 401) {
     
    clear401Data()
    redirectSSO('replace','/')
    //history.push('/login')
  } else {
     
    Sentry.setExtra('fetch_data', rep)
    Sentry.captureMessage('fetch_400_error')
    if(!statusCode) history.push('/errorPage')
  }
}

// 服务端返回的响应码是 2xx的处理
const handleResponse = (res, config) => {
     
  const reponseCode = config.reponseCode
  if (res.code !== '00' && process.env.SENTRY) {
     
    Sentry.setExtra('fetch_data', {
     url: config.newUrl, ...res})
    Sentry.captureMessage('fetch_200_error')
  }
  if (reponseCode) {
     
    return res
  } else if (res.code === '00' || res.status == 200) {
     
    if (window.isApp) {
     
      res.data && res.data.oneid && res.data.oneid.accessToken && window.localStorage.setItem('token', res.data.oneid.accessToken)
    } else {
     
      res.data && res.data.accessToken && window.localStorage.setItem('token', res.data.accessToken)  // 商城
    }
    return res.data
  } else {
     
    Toast.info(res.message, 2)
  }
}

// header 处理
let defaultHeaders = {
     
  'Accept': 'application/json',
  'Content-Type': 'application/json;charset=utf-8'
}

function request(config, hasResend = 0) {
     
  let {
      url, body, method, header, dnsType, loadingClass, reponseCode, type = "", cache, browsercachelevel, statusCode } = config
  if (cache && method === "GET" && window.requestDict[url]) {
     
    return window.requestDict[url]
  }

  let newUrl = CONSTANT.BaseURL + (url[0] == "/" ? url.substr(1) : url)
  let headers
  if (dnsType === "carConfig") {
     
    headers = Promise.resolve({
      channelId: "cop_mobile", "Content-Type": "application/json" }) // 新渠道
  } else if (dnsType === "codeToken") {
     
    newUrl = CONSTANT.BasecodeTokenURL + (url[0] == "/" ? url.substr(1) : url)
    headers = Promise.resolve({
      "Content-Type": "application/json" }) // 新渠道
  } else {
     
    headers = Promise.resolve({
      ...defaultHeaders, 'X-Channel': window.isApp ? '1002' : '1000', 'X-Access-Token': localStorage.getItem('token') || '', ...header })
  }

  const ret = headers.then(headers => {
     
    handleRequest({
      url: newUrl, loadingClass, reponseCode })
    status200 = false
    if (window.fetch) {
     
      const requestConfig = {
     
        credentials: "same-origin",
        method: method || "GET",
        headers,
        mode: "cors",
        cache: browsercachelevel || 'default'
      }

      if (method === "POST" || method === "PUT") {
     
        Object.defineProperty(requestConfig, "body", {
     
          value: type === 'file' ? body : JSON.stringify(body)
        })
        if (type === 'file') {
     
          delete requestConfig.headers["Content-Type"]
        }
      }
      return new Promise((resolve, reject) => {
     
        fetch(newUrl, requestConfig)
          .then(response => {
     
            Loading(false, loadingClass)
            const rep = handleResponseHeader(response.headers.get('x-token-expired'), response, statusCode)
            return rep.json()
          }, error => {
     
            console.error('fetch_error: ', error)
            if(window.isApp) {
     
              isNetworkConnected().then(res => {
     
                showNoNetPage(!res.isConnected)
              })
            } else {
     
              if(!navigator.onLine) history.push('/notNetwork?fetch')
            }
          })
          .then(res => {
     
            if (window.isApp && res.code === '40101' && hasResend < 1) {
     
              reject('resend')
            } else {
     
              resolve(handleResponse(res, {
      url, newUrl, _cache: cache, method, loadingClass, reponseCode }))
            }
          }, error => {
     
            if (error.response) {
     
              reject(error.response.data)
            } else {
     
              reject(error)
            }
            console.error(error)
          })
      })
    } else {
     
      return new Promise((resolve, reject) => {
     
        let requestObj
        if (window.XMLHttpRequest) {
     
          requestObj = new XMLHttpRequest()
        } else {
     
          requestObj = new ActiveXObject() //eslint-disable-line
        }

        const sendData = JSON.stringify(body)

        requestObj.open(method, newUrl, true)

        Object.keys(headers).forEach(key => {
     
          requestObj.setRequestHeader(key, headers[key])
        })
        requestObj.send(sendData)

        requestObj.onreadystatechange = () => {
     
          Loading(false, loadingClass)
          if (requestObj.readyState === 4) {
     
            const rep = handleResponseHeader(requestObj.getResponseHeader('x-token-expired'), requestObj, statusCode)
            if (rep && requestObj.status === 200) {
     
              let obj = requestObj.response

              if (typeof obj !== "object") {
     
                obj = JSON.parse(obj)
              }
              resolve(handleResponse(obj, {
      url, _cache: cache, method, loadingClass, reponseCode }))
            } else {
     
              console.log(requestObj)
              reject(requestObj)
            }
          }
        }
      })
    }
  })
  if (cache && method === "GET" && status200) {
     
    window.requestDict[url] = ret
  }
  return ret
}

export default function sendRequest(config) {
     
  return new Promise(function(resolve, rejected){
     
    request(config).then(r => {
     
      resolve(r)
    }).catch(err => {
     
      if(window.isApp && err === 'resend') {
     
        getAppLogin().then(t => {
     
          if(t) {
     
            config.cache = false
            config.browsercachelevel = 'reload'
            request(config, 1).then(res => {
     
              resolve(res)
            }).catch(e => {
     
              console.log('resend request error: ', e)
            })
          } else {
     
            rejected('error in getAppLogin')
          }
        })
      } else {
     
        rejected(err)
      }
    })
  })
}

你可能感兴趣的:(react,面试)