美文网首页
fetch的二次封装

fetch的二次封装

作者: 得到世界又如何我的心中只有你 | 来源:发表于2020-06-11 17: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.请求和响应参数可能会进行加解密

    相关文章

      网友评论

          本文标题:fetch的二次封装

          本文链接:https://www.haomeiwen.com/subject/aztbtktx.html