再谈from属性EncType与axios分装—axios拦截器实现-源码浅析

923 阅读3分钟

中古时代(若干年前)使用angular的时候,总结过《from属性EncType提交数据的格式详解—在angular中的应用

在远古ie兴盛的时代,基本是fromData提交数据,ajax+jquery推动了时代的变革,当数据提交也大抵如此,直到angularJS到来,前后端才通用json形式,转眼从react跳转到vue(感觉被Vue强暴),闲话打住

理论上,一套api接口,一般统一json格式,要么统一fromData,但是,就是有不按套路出牌(后端屌啊),三个都有

application/x-www-form-urlencoded

multipart/form-data

application/json


同时,接口返回数据,理论上应该统一规划,比如消息属性(toast统一处理),数据分层,但是,泪崩

axios封装是必须,但是,前端时候也得考虑下规范(架构设计)方面的问题——小白秉性暴露无遗


看了axios源码

+axios

index.js

index.d.ts

+lib

axios.js

+core

Axios.js

axios本身就会检测数据,匹配不同Content-Type

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;
}],

但是,实际提交都是 Object类型,于是就得转

第一种处理模式,就是prototype大法,

axios.postForm = function (url, data, config = null) {
  return new Promise(function (resolve, reject) {
    config = {
      method: 'post',
      url: url,
      data: () => {
        let fromData = new FormData();
        for (let i in data) {
          fromData.append(i,data[i])
        }
        return fromData;
      }
    };
    axios.request(config).then((response) => {
      resolve(response)
    }, err => {
      reject(err);
    })
  })
};

第二种,重新构造一个新的函数,call回调,或者

class http {
  constructor(config) {
    if (config) {
      return new Promise((resolve, reject) => {
        axios(config)
          .then(function (response) {

          });
      });
    }
  }
  static get(url, parma) {}
  static post(url, param) {}
}


发现在var axios= Create an instance of Axios,axios get post request 都是集中处理

Axios.prototype.request

// Provide aliases for supported request methods
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
  /*eslint func-names:0*/
  Axios.prototype[method] = function(url, config) {
    return this.request(utils.merge(config || {}, {
      method: method,
      url: url
    }));
  };
});

utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
  /*eslint func-names:0*/
  Axios.prototype[method] = function(url, data, config) {
    return this.request(utils.merge(config || {}, {
      method: method,
      url: url,
      data: data
    }));
  };
});

于是决定,通过增加一个属性声明,如:commitType:'form'

于是,就会有如下代码


import axios from 'axios';
import queryString from 'queryString';//nodeJs内置,无需npm i
axios.interceptors.request.use(function (config) {
  //TODO 请求拦截
  /*store.commit('updateLoadingStatus', {isLoading: true});*/
  if (config.commitType) {
    if (config.commitType === 'form') {
      config.headers['Content-Type'] = 'application/x-www-form-urlencoded';
      config.transformRequest = [function (data) {
        return queryString.stringify(data);//利用对应方法转换格式
      }]
    } else if (config.commitType === 'url') {
      config.headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
      config.transformRequest = [function (data) {
        return decodeURIComponent(data);
      }];
    }
  }

  console.log(config);
  return config;
}, function (error) {
  //请求错误时做些事
  return Promise.reject(error);
});

//响应拦截器即异常处理
axios.interceptors.response.use(response => {
  //TODO 统一处理逻辑
  //store.commit('updateLoadingStatus', {isLoading: false});
  if (response.data) {
    return response.data;
  }
  return response
}, err => {
  if (err && err.response) {
    //http状态码处理
    switch (err.response.status) {
      case 400:
        err.msg = '错误请求';
        break;
      case 401:
        err.msg = '未授权,请重新登录';
        break;
      case 403:
        err.msg = '拒绝访问';
        break;
      case 404:
        err.msg = '请求错误,未找到该资源';
        break;
      case 405:
        err.msg = '请求方法未允许';
        break;
      case 408:
        err.msg = '请求超时';
        break;
      case 500:
        err.msg = '服务器端出错';
        break;
      case 501:
        err.msg = '网络未实现';
        break;
      case 502:
        err.msg = '网络错误';
        break;
      case 503:
        err.msg = '服务不可用';
        break;
      case 504:
        err.msg = '网络超时';
        break;
      case 505:
        err.msg = 'http版本不支持该请求';
        break;
      default:
        err.msg = `连接错误${err.response.status}`
    }
  } else {
    err.msg = '连接到服务器失败';
  }
  return Promise.resolve(err.response)
});
//超时时间
axios.defaults.timeout = 5000;

export default axios;

拓展文章:

Vue中axios的使用技巧配置项详解

Vue基于vuex、axios拦截器实现loading效果及axios的安装配置

原文链接:www.zhoulujun.cn/html/webfro…(不定时更新)

文有不妥之处,请留言告知,谢谢!