vue+axios x-www-form-urlencoded参

2018-06-25  本文已影响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
}
上一篇下一篇

猜你喜欢

热点阅读