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)
      }
    })
  })
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值