美文网首页
vue+axios x-www-form-urlencoded参

vue+axios x-www-form-urlencoded参

作者: 碧波之心 | 来源:发表于2018-06-25 17:21 被阅读201次

    前言

    在使用vue-resource的时候,想要使post传参为x-www-form-urlencoded类型的content-type,只需要增加一行配置Vue.http.options.emulateJSON = true就可以解决问题。但是到了axios就没有那么简单了。进过分析、尝试。最终解决了问题。以下是我的解决方案。网上有很多解决方案。我没有采纳,也就没有去尝试。

    网上的方法

    网上找到的解决方案基本差不多。用URLSearchParams,却说兼容性不好,而且要改请求的代码,这样太严重了,要改太多接口。新项目还可以试,老项目已经一大堆的请求。去一个一个改很难接受。还有些方案描述的不清楚,貌似适合他所在的项目中。或者有环境依赖的。不一一去说了。找了很久没有觉得符合我想要的结果。

    源码分析

    经过查看源码,发现以下一段代码:

    var defaults = {
      adapter: getDefaultAdapter(),
    
      transformRequest: [function transformRequest(data, headers) {
        normalizeHeaderName(headers, 'Content-Type');
        if (utils.isFormData(data) ||
          utils.isArrayBuffer(data) ||
          utils.isBuffer(data) ||
          utils.isStream(data) ||
          utils.isFile(data) ||
          utils.isBlob(data)
        ) {
          return data;
        }
        if (utils.isArrayBufferView(data)) {
          return data.buffer;
        }
        if (utils.isURLSearchParams(data)) {
          setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8');
          return data.toString();
        }
        if (utils.isObject(data)) {
          setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
          return JSON.stringify(data);
        }
        return data;
      }],
    }
    ...
    

    看得出,不段代码中如果传的参数是URLSearchParams对象的,使用x-www-form-urlencoded的Content-Type。所以网上说的那种方案是可行的。
    其实axios默认的content-type是application/x-www-form-urlencoded;charset=utf-8。只是参数对象在其它判断都不通过,isObject的时候才会是json。
    这是axios默认配置中的一项,transformRequest这是一个数组。我就想,如果数组里有多个项的话会是怎么执行呢。
    找到如下代码:

    module.exports = function transformData(data, headers, fns) {
      /*eslint no-param-reassign:0*/
      utils.forEach(fns, function transform(fn) {
        data = fn(data, headers);
      });
    
      return data;
    };
    

    原来如果transformRequest数组中有多个转换器的时候,它会挨个执行,实现了转换器链。

    解决问题

    经过源码分析,要解决这个访问就简单了。向axios的全局配置中加入一个转换器。我觉得应该加默认转换器前面。就不需要设置Content-Type了。

    const customTransformData = (data, headers) => {
      if (utils.isFormData(data) ||
        utils.isArrayBuffer(data) ||
        utils.isBuffer(data) ||
        utils.isStream(data) ||
        utils.isFile(data) ||
        utils.isBlob(data) ||
        utils.isArrayBufferView(data) ||
        utils.isURLSearchParams(data)
      ) {
        return data
      }
      if (utils.isObject(data)) {
        for (var pkey in data) {
          if (data[pkey] === null || typeof (data[pkey]) === 'undefined') {
            delete data[pkey]
          }
        }
        data = utils.params(data)
        return data
      }
      return data
    }
    
    // 加入到数据最前面
    axios.defaults.transformRequest.unshift(customTransformData)
    

    为了不影响其它转换器的执行。我只是把isObject的做了处理。
    其中:
    utils:复制了axios中的utils的相应函数。
    utils.params:这是参考了vue-resource中参数转换的代码,加入到utils中的。
    以下是utils的代码,供参考

    import _ from 'lodash'
    
    var isBuffer = _.isBuffer
    
    /* global toString:true */
    
    // utils is a library of generic helper functions non-specific to axios
    
    var toString = Object.prototype.toString
    
    /**
     * Determine if a value is an ArrayBuffer
     *
     * @param {Object} val The value to test
     * @returns {boolean} True if value is an ArrayBuffer, otherwise false
     */
    function isArrayBuffer (val) {
      return toString.call(val) === '[object ArrayBuffer]'
    }
    
    /**
     * Determine if a value is a FormData
     *
     * @param {Object} val The value to test
     * @returns {boolean} True if value is an FormData, otherwise false
     */
    function isFormData (val) {
      return (typeof FormData !== 'undefined') && (val instanceof FormData)
    }
    
    /**
     * Determine if a value is a view on an ArrayBuffer
     *
     * @param {Object} val The value to test
     * @returns {boolean} True if value is a view on an ArrayBuffer, otherwise false
     */
    function isArrayBufferView (val) {
      var result
      if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) {
        result = ArrayBuffer.isView(val)
      } else {
        result = (val) && (val.buffer) && (val.buffer instanceof ArrayBuffer)
      }
      return result
    }
    
    /**
     * Determine if a value is an Object
     *
     * @param {Object} val The value to test
     * @returns {boolean} True if value is an Object, otherwise false
     */
    function isObject (val) {
      return val !== null && typeof val === 'object'
    }
    
    /**
     * Determine if a value is a File
     *
     * @param {Object} val The value to test
     * @returns {boolean} True if value is a File, otherwise false
     */
    function isFile (val) {
      return toString.call(val) === '[object File]'
    }
    
    /**
     * Determine if a value is a Blob
     *
     * @param {Object} val The value to test
     * @returns {boolean} True if value is a Blob, otherwise false
     */
    function isBlob (val) {
      return toString.call(val) === '[object Blob]'
    }
    
    /**
     * Determine if a value is a Function
     *
     * @param {Object} val The value to test
     * @returns {boolean} True if value is a Function, otherwise false
     */
    function isFunction (val) {
      return toString.call(val) === '[object Function]'
    }
    
    /**
     * Determine if a value is a Stream
     *
     * @param {Object} val The value to test
     * @returns {boolean} True if value is a Stream, otherwise false
     */
    function isStream (val) {
      return isObject(val) && isFunction(val.pipe)
    }
    
    /**
     * Determine if a value is a URLSearchParams object
     *
     * @param {Object} val The value to test
     * @returns {boolean} True if value is a URLSearchParams object, otherwise false
     */
    function isURLSearchParams (val) {
      return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams
    }
    
    /**
     * Encodes a Url parameter string.
     *
     * @param {Object} obj
     */
    function params (obj) {
      let params = []
      let escape = encodeURIComponent
      params.add = function (key, value) {
        if (_.isFunction(value)) {
          value = value()
        }
        if (value === null) {
          value = ''
        }
        this.push(escape(key) + '=' + escape(value))
      }
      serialize(params, obj)
      return params.join('&').replace(/%20/g, '+')
    }
    
    function serialize (params, obj, scope) {
      let array = _.isArray(obj)
      let plain = _.isPlainObject(obj)
      let hash = null
      _.forEach(obj, (value, key) => {
        hash = _.isObject(value) || _.isArray(value)
        if (scope) {
          key = scope + '[' + (plain || hash ? key : '') + ']'
        }
        if (!scope && array) {
          params.add(value.name, value.value)
        } else if (hash) {
          serialize(params, value, key)
        } else {
          params.add(key, value)
        }
      })
    }
    
    export default {
      isArrayBuffer: isArrayBuffer,
      isBuffer: isBuffer,
      isFormData: isFormData,
      isArrayBufferView: isArrayBufferView,
      isObject: isObject,
      isFile: isFile,
      isBlob: isBlob,
      isStream: isStream,
      isURLSearchParams: isURLSearchParams,
      params: params
    }
    

    相关文章

      网友评论

          本文标题:vue+axios x-www-form-urlencoded参

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