这一章主要实现一些配置化,让用户可以进行配置
目录:
添加 defaults.ts
:
import {AxiosRequestConfig} from './types';
const defaults: AxiosRequestConfig = {
method: 'get',
timeout: 0,
headers:{
common: {
Accept: 'application/json, text/plain, */*',
}
},
}
const methodsNoData = ['delete','get','head','options'];
methodsNoData.forEach(method => {
defaults.headers[method] = {}
})
const methodsWithData = ['post','put','patch'];
methodsWithData.forEach(method => {
defaults.headers[method] = {
'Content-Type': 'application/x-www-form-urlencoded',
}
})
export default defaults;
这个文件主要是定义一些默认配置。
添加 core/mergeConfig.ts
文件
import { AxiosRequestConfig } from '../types';
import { isPlainObject,deepMerge } from '../helpers/util';
const strats = Object.create(null);
function defaultStart(val1:any,val2:any):any {
return typeof(val2) !== 'undefined' ? val2: val1;
}
function formval2Start(val1:any,val2:any):any {
if(typeof val2 !== 'undefined') {
return val2;
}
}
function deepMergeStrat(val1: any,val2:any): any {
debugger;
if(isPlainObject(val2)) {
return deepMerge(val1,val2);
} else if(typeof val2 !== 'undefined') {
return val2
} else if(isPlainObject(val1)) {
return deepMerge(val1);
} else if(typeof val1 !== 'undefined') {
return val1;
}
}
const stratKeysFromVal2 = ['url','params','data'];
stratKeysFromVal2.forEach(key => {
strats[key] = formval2Start
})
const stratKyesDeepMerge = ['headers']
stratKyesDeepMerge.forEach(key => {
strats[key] = deepMergeStrat;
})
export default function mergeConfig(config1:AxiosRequestConfig,config2?:AxiosRequestConfig):AxiosRequestConfig{
if(!config2) {
config2 = {}
}
const config = Object.create(null);
for(let key in config2) {
mergeField(key);
}
for(let key in config1) {
if(!config2[key]) {
mergeField(key);
}
}
function mergeField(key: string):void {
const strat = strats[key] || defaultStart
config[key] = strat(config1[key],config2![key]);
}
return config;
}
这个文件主要把默认配置和用户自己配置的进行合并。
这里定义了几种合并方式,其中 url、params、data 采用 stratKeysFromVal2 方法,主要意思是:只要 val2 有数据,就返回 val2 ; headers 采用的是 deepMergeStrat 方法,主要是进行深拷贝,将 val1 和 val2 合并成一个对象;其他就采用 defaultStart ,主要是:如果 val2 有数据,就返回 val2 ,否则返回 val1。
在 helpers/util.ts
中新添加了一个方法 deepMerge :
// ...
export function deepMerge(...objs: any[]) : any {
const result = Object.create(null);
objs.forEach(obj => {
if(obj) {
Object.keys(obj).forEach(key => {
const val = obj[key];
if(isPlainObject(val)) {
if(isPlainObject(result[key])) {
result[key] = deepMerge(result[key],val)
} else {
result[key] = deepMerge(val);
}
} else {
result[key] = val
}
})
}
})
return result;
}
这个函数实现的是 深拷贝。
在 core/Axios.ts
添加两句话:
// ...
import mergeConfig from './mergeConfig';
// ...
request(url: any, config?:any):AxiosPromise {
if(typeof url === 'string') {
if(!config) {
config = {}
}
config.url = url;
} else {
config = url;
}
config = mergeConfig(this.defaults, config); // 添加一句
// ...
}
在 core/dispatchRequest.ts
添加两句话:
// ..
import { flattenHeaders } from '../helpers/header';
// ..
function processConfig(config: AxiosRequestConfig): void {
// ...
config.headers = flattenHeaders(config.headers,config.method!);
}
在 helpers/header.ts
添加一个函数:
import { isPlainObject, deepMerge } from "./util";
// ..
export function flattenHeaders(headers: any, method: Method) : any {
if(!headers) {
return headers
}
headers = deepMerge(headers.common,headers[method],headers);
const methodsToDelete = ['delete','get','head','options','post','put','patch','common'];
methodsToDelete.forEach(method => {
delete headers[method]
})
return headers;
}
将 defaults.ts 的配置进行 合并,删除 delete,get,common 等属性,规范话 Header
这样 默认 配置写完了
在 types/index.ts
最后添加:
// ..
export interface AxiosRequestConfig {
// ..
transformRequest?: AxiosTransformer | AxiosTransformer[],
transformResponse?: AxiosTransformer | AxiosTransformer[],
// ..
}
// ..
export interface AxiosTransformer {
(data:any,headers?:any) : any,
}
新增 core/transform.ts
文件
import { AxiosTransformer } from "../types";
export default function transform(data:any,headers: any,fns:AxiosTransformer | AxiosTransformer[]) : any {
if(!fns) {
return data
}
if(!Array.isArray(fns)){
fns = [fns];
}
fns.forEach(fn => {
data = fn(data,headers);
})
return data;
}
在 defaults.ts
添加
// ...
import {processHeaders} from './helpers/header'
import {transformRequest,transformResponse} from './helpers/data';
const defaults: AxiosRequestConfig = {
// ...
transformRequest: [
function(data:any,headers:any):any {
processHeaders(data,headers);
return transformRequest(data);
}
],
transformResponse: [
function(data: any):any {
return transformResponse(data)
}],
}
// ..
这个文件将以前写过的 processHeaders
和 transformRequest
和 transformResponse
在 transformRequest 和 transformResponse 中进行调用。
修改过后的 core/dispatchRequest.ts
文件
import {AxiosRequestConfig,AxiosPromise, AxiosResponse} from '../types';
import xhr from './xhr';
import { buildURL } from '../helpers/url';
import { flattenHeaders } from '../helpers/header';
import transform from './transform';
export default function dispatchRequst (config :AxiosRequestConfig) : AxiosPromise {
processConfig(config);
return xhr(config).then(res => {
return transformResponseData(res);
});
}
function processConfig(config: AxiosRequestConfig): void {
config.url = transformURL(config);
config.data = transform(config.data,config.headers,config.transformRequest!);
config.headers = flattenHeaders(config.headers,config.method!);
}
function transformURL (config: AxiosRequestConfig) :string {
const {url,params} = config;
return buildURL(url!,params);
}
function transformResponseData(res:AxiosResponse):AxiosResponse {
res.data = transform(res.data,res.headers,res.config.transformResponse!);
return res;
}
这样就写完了。
在 types/index.ts
新添加一个接口
// ...
export interface AxiosStatic extends AxiosInstance {
create(config?:AxiosRequestConfig): AxiosInstance
}
// ...
在 axios.ts
文件中把 AxiosInstance 修改成 AxiosStatic 添加 create API 接口
import {AxiosStatic, AxiosRequestConfig} from './types';
import Axios from './core/Axios';
import {extend} from './helpers/util';
import defaults from './defaults';
import mergeConfig from './core/mergeConfig';
function createInstance(config:AxiosRequestConfig):AxiosStatic{
const context = new Axios(config);
const instance = Axios.prototype.request.bind(context); // 绑定 作用域
extend(instance,context);
return instance as AxiosStatic;
}
const axios = createInstance(defaults);
axios.create = function create(config) {
return createInstance(mergeConfig(defaults,config));
}
export default axios;
这一章就写到这里了。