axios源码分析--转换请求数据和响应数据

4,094 阅读2分钟

axios支持转换请求数据和响应数据

使用方式

transformRequest?: AxiosTransformer | AxiosTransformer[];
transformResponse?: AxiosTransformer | AxiosTransformer[];
axios('https://api.github.com/users/mzabriskie', {
  transformResponse:[function (data, headers) {
    //todo
    return data;
  }, function (data, headers) {
    //todo
    return data;
  }],
  transformResponse: [function (data, headers) {
    if (typeof data === 'string') {
        try {
            data = JSON.parse(data);
        } catch (e) { /* Ignore */ }
    }
    return data;
 }],
}).then(()=>{
    
}).catch(()=>{
    
})

transformRequest和transformResponse一样使用方式

源码分析

axios源码分析--请求流程传送门,axios源码分析--拦截器传送门`

axios(url, config),实际是调用Axios.prototype.request方法。Axios.prototype.request方法中链式调用chain相当于

Promise.resolve(config)
.then(interceptors.request, interceptors.request)
...//多个请求拦截器
.then(dispatchRequest, undefined)
...//多个响应拦截器
.then(interceptors.response, interceptors.response)

其实dispatchRequest方法才是真正的xhr请求,我们进入axios/lib/core/dispatchRequest.js文件,看看它执行了什么

module.exports = function dispatchRequest(config) {
  //...
  //取消请求的判断
  
  //转换请求数据
  config.data = transformData(
    config.data,
    config.headers,
    config.transformRequest
  );
  //...
  var adapter = config.adapter || defaults.adapter;

  return adapter(config).then(function onAdapterResolution(response) {
    //...
    //取消请求的判断
    
    //转换响应数据
    response.data = transformData(
      response.data,
      response.headers,
      config.transformResponse
    );

    return response;
  }, function onAdapterRejection(reason) {
    if (!isCancel(reason)) {
      //...
     //取消请求的判断
      if (reason && reason.response) {
       // 转换响应数据
        reason.response.data = transformData(
          reason.response.data,
          reason.response.headers,
          config.transformResponse
        );
      }
    }

    return Promise.reject(reason);
  });
};

调用transformData方法进行数据转换,进入到axios/lib/core/transformData.js文件

function transformData(data, headers, fns) {
  utils.forEach(fns, function transform(fn) {
    data = fn(data, headers);
  });

  return data;
};

其实就是将transformRequest或者transformResponse这样的函数数组,传递data和headers参数,在请求前和响应后对data数据和header数据进行一些定制化处理

defaults中定义有默认transformRequest和transformResponse方法

var defaults = {
    //...
    transformRequest: [function transformRequest(data, headers) {
        normalizeHeaderName(headers, 'Accept');
        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;
  }],

  transformResponse: [function transformResponse(data) {
    if (typeof data === 'string') {
      try {
        data = JSON.parse(data);
      } catch (e) { /* Ignore */ }
    }
    return data;
  }],
  //...
}

直接transformResponse:[],会把defaults.transformResponse覆盖掉,如果想在默认上进行添加,可以像如下定义方式

transformResponse: axios.defaults.transformResponse.concat(function(){
    //todo
})

在请求配置config中data是post会传递的数据,params是拼接到url后的参数。默认的transformRequest方法,根据不同的data数据类型,对header和自身进行一些设置