fetch的二次封装

2020-06-11  本文已影响0人  得到世界又如何我的心中只有你
前言

在请求方法这块,考虑到便捷性,针对不同的平台app web h5以及对参数的处理,做了以下的方法封装。

内容

1.请求参数处理
2.响应code处理
3.处理数组、对象等特殊参数
4.跨域请求mode
5.拓展

执行
请求参数处理

这里主要使用到三种请求头类型:multipart/form-data、application/json、application/x-www-form-urlencoded,针对不同的类型对参数做不同的处理

/**
 * @param {*} params 
 * @param {*} ContentType 
 */
function getUriParams(params = {}, contentType = 'multipart/form-data') {
    // 请求参数
    let uriParams = ''
    switch (contentType) {
        case 'multipart/form-data': // formData
            uriParams = new FormData()
            Object.keys(params).forEach(key => {
                uriParams.append(key, params[key])
            })
            break
        case 'application/json': // json
            uriParams = JSON.stringify(params)
            break
        case 'application/x-www-form-urlencoded': // 键值对 key1=value1&key2=value2
            Object.keys(params).forEach(key => {
                uriParams += key + '=' + params[key] + '&'
            })
            uriParams = uriParams.substring(0, uriParams.length - 1)
            break
        default:
            break
    }
    return uriParams
}
响应code处理

常用的200 404 500...,以及项目中单独定义的。

/**
 * @param {Object} respResult 
 * @param {Function} resolve 
 * @param {Function} reject 
 */
function responseCode(respResult = {}, resolve, reject) {
    switch (respResult.code) {
        case 200: // 成功
            resolve(respResult.ret)
            break
        case 404: // 请求资源不存在
            resolve({ msg: '请求资源不存在' })
            break
        case 500: // 服务器异常
            resolve({ msg: '服务器异常' })
            break
        // 以下为项目中接口定义的code
        case xxx: // 鉴权失败
            doLogin()
            break
        // ... ... 
        default:
            reject(respResult)
            break
    }
}
处理数组、对象等特殊参数

在请求类型为formData时,请求携带参数格式为

  id = 1
  value = '1234'
  // ... ...

当后端接受类型存在Map List时,我们的请求参数格式可能为

params = {
  list1: [1,2,3,4],
  list2: [{id: 1, value: '1234'}],
  obj1: {id: 1, value: '1234'}
  // ... ...
}

而我们知道需要将数据调整成下面的方式才能被后端所识别

params['list1'][0] = 1
params['list1'][1] = 2
// ... ...
params['list2'][0]['id'] = 1
params['list2'][0]['value'] = '1234'
// ... ...
params['obj1']['id'] = 1
params['obj1']['value'] = '1234'
// ... ...

注意:针对图片格式则不用做相应处理

/**
 * 参数处理(处理数组或对象的value,格式:数组arr[i]、对象obj.key)
 * @param {*} params 
 */
function manageParams(params) {
    for (let key in params) {
        let item = params[key]
        if (item && item !== '' && item !== null && item !== undefined) {
            if (Array.isArray(item)) {
                // 数组
                item.forEach((val, i) => {
                    if (val.constructor === Object || val.constructor === File || typeof val === 'string' || typeof val === 'number') {
                        params[`${key}[${i}]`] = val
                    }
                })

                delete params[key]
                manageParams(params)
            } else if (item.constructor === Object && !isImgFile(item)) {
                // 对象
                for (let i in item) {
                    params[`${key}.${i}`] = item[i]
                }
                delete params[key]
                manageParams(params)
            }
        }
    }

    let allString = false
    for (let key in params) {
        let item = params[key] || ''
        if (typeof item === 'string' || typeof item === 'number' || item === null || item.constructor === File) {
            allString = true
        }
    }
    if (allString) {
        return params
    }
}

// 非图片
function isImgFile(obj) {
    if (obj['size'] && obj['type'] && obj['name']) {
        return true
    }
    return false
}
跨域请求mode

fetch支持cors进行跨域访问,但如果header中需要携带参数,会进行一个预检的过程,需要服务端设置允许请求头携带参数

// ... ...
let headers = new Header()
headers['Access-Control-Allow-Origin'] = '*'
headers['Content-Type'] = 'xxx'
// ... ...
fetch(url, {
   method: 'POST',
   headers,
   mode: 'cors',
   body: getUriParams(manageParams(params)),
}).then(() {
    // ... ...
})
// ... ...

服务端设置

setHeader('Access-Control-Allow-Headers: Content-Type ... ...');
拓展

根据项目具体情况
1.参数可能放于body或者header

return new Promise((reject, resolve) => {
  fetch(url, {
     method: 'POST',
     headers: {
        'Content-Type': ContentType,
        platformType: 2,
        osType: '',
        version: ''
        // ... ...
     },
     body: getUriParams(manageParams(params)),
     credentials: 'include'
  }).then((response) => {
     Fetch.Fetch_last_url[url] = null
     if (response.ok) {
         return response.json()
      } else {
         reject({success: false, errCode:'500', errDesc: '服务器异常,请稍后重试'})
      }
   }).then((respResult) => {
        responseCode(respResult, resolve, reject)
   }).catch((error) => {
        reject({success: false, errCode:'500', error: error.errDesc})
   })
})

2.可能会使用到签名校验

function getSign(params) {
    const CryptoJS = require('crypto-js')
    // 密钥
    let secret = '3f3**************************216'  // 默认固定密钥
    // 排序、加密(签名字段按照key正序,前后拼接密钥,MD5)
    let paramsKeys = [], allParams = secret
    Object.keys(params).forEach(key => paramsKeys.push(key))
    paramsKeys.sort()
    paramsKeys.forEach((key) => allParams += key + '=' + params[key] + '&')

    allParams = allParams.substring(0, allParams.length - 1) + secret
    return CryptoJS.MD5(allParams).toString()
}

3.请求和响应参数可能会进行加解密

上一篇下一篇

猜你喜欢

热点阅读