Aktuelle PicturePeople Gutscheine & Deals

PicturePeople Logo
Gültig bis 31. Oktober 2025

PicturePeople Gutschein: Gratis Mini-Shooting

# 1. 前言 在上一篇文章中,我们实现了axios的请求和响应拦截器功能,并且为它们编写了对应的测试用例。接下来,我们就来实现axios的配置化,所谓配置化是指:我们希望能够对每次请求的配置进行设定,设定一些公共的默认配置,并且还可以在每次请求中自定义配置,并且自定义配置优先级高于默认配置。 # 2. 需求分析 我们希望axios可以有默认配置,并且还可以在每次请求中传入自定义配置,自定义配置可以覆盖默认配置,并且希望默认配置和自定义配置可以合并。如下: typescript // 默认配置 axios.defaults.headers.common["test"] = 1; axios.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded"; // 自定义配置 const instance = axios.create({ headers: { test: 2, }, }); instance.get("/more/get", { headers: { test: 3, }, }); 对于headers这类复杂对象属性,我们需要进行深拷贝,同时也处理了其它一些情况,如下: typescript axios.defaults.baseURL = "https://api.example.com"; // 默认配置 axios.defaults.headers.common["test"] = 1; // 自定义配置 const instance = axios.create({ baseURL: "https://img.example.com", headers: { test: 2, }, }); instance.get("/more/get", { headers: { test: 3, }, }); 合并后的配置应该是: json { "baseURL": "https://img.example.com", "headers": { "common": { "test": 1 }, "test": 3 } } # 3. 默认配置 首先,我们先来实现默认配置。默认配置我们可以在src/axios.ts中定义,如下: typescript // src/axios.ts const defaults: AxiosRequestConfig = { 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", }; }); 我们定义了defaults常量,它包含默认配置。对于headers,我们定义了common和一些请求方法的headers,common表示对于任何类型的请求都要添加该header,而对于get、post等方法,也会添加对应的header,但是会覆盖common中相同的header。 # 4. 合并策略 合并策略我们采用与axios官方相同的策略,如下: typescript // src/core/mergeConfig.ts import { AxiosRequestConfig } from "./types"; import { deepMerge, isPlainObject } from "./util"; const strats = Object.create(null); function defaultStrat(val1: any, val2: any): any { return typeof val2 !== "undefined" ? val2 : val1; } function fromVal2Strat(val1: any, val2: any): any { if (typeof val2 !== "undefined") { return val2; } } function deepMergeStrat(val1: any, val2: any): any { 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] = fromVal2Strat; }); const stratKeysDeepMerge = ["headers"]; stratKeysDeepMerge.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] || defaultStrat; config[key] = strat(config1[key], config2![key]); } return config; } 合并规则如下: - 对于url、params、data这些属性,默认使用config2中的配置,即自定义配置。 - 对于headers这类复杂对象,采用深拷贝的方式,并且会合并config1和config2中的配置。 - 对于其他属性,采用默认策略,即如果config2中有配置,则使用config2中的配置,否则使用config1中的配置。 # 5. 修改 axios 函数 接下来,我们需要修改src/axios.ts中的axios函数,让它支持默认配置和自定义配置的合并。 typescript // src/axios.ts import { AxiosRequestConfig, AxiosPromise, Method } from "./types"; import dispatchRequest from "./core/dispatchRequest"; import InterceptorManager from "./core/InterceptorManager"; import mergeConfig from "./core/mergeConfig"; interface Interceptors { request: InterceptorManager; response: InterceptorManager; } interface PromiseChain { resolved: InterceptorResolved | ((config: AxiosRequestConfig) => AxiosPromise); rejected?: InterceptorRejected; } export default class Axios { defaults: AxiosRequestConfig; interceptors: Interceptors; constructor(initConfig: AxiosRequestConfig) { this.defaults = initConfig; this.interceptors = { request: new InterceptorManager(), response: new InterceptorManager(), }; } request(url: any, config?: any): AxiosPromise { if (typeof url === "string") { if (!config) { config = {}; } config.url = url; } else { config = url; } config = mergeConfig(this.defaults, config); const chain: PromiseChain[] = [ { resolved: dispatchRequest, rejected: undefined, }, ]; this.interceptors.request.forEach((interceptor) => { chain.unshift(interceptor); }); this.interceptors.response.forEach((interceptor) => { chain.push(interceptor); }); let promise = Promise.resolve(config); while (chain.length) { const { resolved, rejected } = chain.shift()!; promise = promise.then(resolved, rejected); } return promise; } get(url: string, config?: AxiosRequestConfig): AxiosPromise { return this._requestMethodWithoutData("get", url, config); } delete(url: string, config?: AxiosRequestConfig): AxiosPromise { return this._requestMethodWithoutData("delete", url, config); } head(url: string, config?: AxiosRequestConfig): AxiosPromise { return this._requestMethodWithoutData("head", url, config); } options(url: string, config?: AxiosRequestConfig): AxiosPromise { return this._requestMethodWithoutData("options", url, config); } post(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise { return this._requestMethodWithData("post", url, data, config); } put(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise { return this._requestMethodWithData("put", url, data, config); } patch(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise { return this._requestMethodWithData("patch", url, data, config); } _requestMethodWithoutData(method: Method, url: string, config?: AxiosRequestConfig) { return this.request( Object.assign(config || {}, { method, url, }) ); } _requestMethodWithData(method: Method, url: string, data?: any, config?: AxiosRequestConfig) { return this.request( Object.assign(config || {}, { method, url, data, }) ); } } 我们修改了Axios类,在构造函数中传入默认配置,并且在request方法中,我们使用mergeConfig函数合并默认配置和自定义配置。 # 6. 修改默认配置 接下来,我们需要修改src/axios.ts中的默认配置,并且导出axios实例。 typescript // src/axios.ts const defaults: AxiosRequestConfig = { 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", }; }); const axios = new Axios(defaults); export default axios; # 7. 修改 create 函数 我们还需要修改src/axios.ts中的create函数,让它支持创建新的axios实例。 typescript // src/axios.ts export 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; # 8. 编写测试用例 接下来,我们编写测试用例来测试我们的配置合并功能。 typescript // test/config.spec.ts import axios from "../src/index"; import mergeConfig from "../src/core/mergeConfig"; describe("config", () => { it("should merge config", () => { const config1 = { url: "config1", data: { foo: "bar", }, }; const config2 = { url: "config2", params: { bar: "foo", }, }; const merged = mergeConfig(config1, config2); expect(merged.url).toBe("config2"); expect(merged.data).toEqual({ foo: "bar" }); expect(merged.params).toEqual({ bar: "foo" }); }); it("should merge config with headers", () => { const config1 = { headers: { common: { Accept: "application/json, text/plain, */*", }, get: { "X-Requested-With": "XMLHttpRequest", }, }, }; const config2 = { headers: { common: { "X-Test": "test", }, post: { "X-Test2": "test2", }, }, }; const merged = mergeConfig(config1, config2); expect(merged.headers.common).toEqual({ Accept: "application/json, text/plain, */*", "X-Test": "test", }); expect(merged.headers.get).toEqual({ "X-Requested-With": "XMLHttpRequest", }); expect(merged.headers.post).toEqual({ "X-Test2": "test2", }); }); it("should merge config with deep properties", () => { const config1 = { auth: { username: "foo", password: "bar", }, }; const config2 = { auth: { username: "baz", }, }; const merged = mergeConfig(config1, config2); expect(merged.auth).toEqual({ username: "baz", password: "bar", }); }); it("should merge config with undefined", () => { const config1 = { timeout: 1000, }; const config2 = { timeout: undefined, }; const merged = mergeConfig(config1, config2); expect(merged.timeout).toBe(1000); }); it("should merge config with null", () => { const config1 = { timeout: 1000, }; const config2 = { timeout: null, }; const merged = mergeConfig(config1, config2); expect(merged.timeout).toBeNull(); }); }); # 9. 总结 至此,我们就实现了axios的配置化功能,并且编写了对应的测试用例。在下一篇文章中,我们将实现axios的取消功能。

XXXXXXI-25 Gutschein anzeigen
PicturePeople Logo
Gültig bis 31. Oktober 2025

PicturePeople Gutschein: Gratis Mini-Shooting

XXXXXXI-25 Gutschein anzeigen
PicturePeople Logo
Gültig bis 15. Oktober 2025

PicturePeople Angebot: Iris-Fotografie ab 49,99€

Folgt unserem Link, um das Angebot kennenzulernen. Weitere Infos auf der Aktionsseite. Einen Gutscheincode benötigt ihr nicht.

Deal anzeigen
PicturePeople Logo
Gültig bis 15. Oktober 2025

PicturePeople Angebot: Familien-Fotoshooting ab 49,99€

Folgt unserem Link, um das Angebot kennenzulernen. Weitere Infos auf der Aktionsseite. Einen Gutscheincode benötigt ihr nicht.

Deal anzeigen
PicturePeople Logo
Gültig bis 15. Oktober 2025

PicturePeople Angebot: Geschenkgutscheine ab 10,00€

Folge einfach unserem Link Anschließend kannst du Geschenkgutscheine im Wert von 10 Euro bis 800 Euro bestellen

Deal anzeigen
PicturePeople Logo
Gültig bis 15. Oktober 2025

PicturePeople Angebot: Fotostudio finden

Folgt unserem Link, um das Angebot kennenzulernen. Weitere Infos auf der Aktionsseite. Einen Gutscheincode benötigt ihr nicht.

Deal anzeigen

Abgelaufene PicturePeople Gutscheine & Deals

Abgelaufen
PicturePeople Logo
abgelaufen am: 11.05.25

Muttertag-Special

Gilt für Fotoshootings Nicht kombinierbar mit anderen Aktionen. Keine Barauszahlung.

Abgelaufen
PicturePeople Logo
abgelaufen am: 30.04.25

25,00€ Rabatt

Gilt beim Ferien-Special auf ein Mini-Fotoshooting für Kinder & Familien Folgt unserem Link, um das Angebot kennenzulernen. Weitere Infos auf der Aktionsseite. Einen Gutscheincode benötigt ihr nicht.

Abgelaufen
PicturePeople Logo
abgelaufen am: 21.04.25

100,00€ Rabatt

Gilt beim Oster-Special auf ein Professionelles Fotoshooting mit Bilderpaket Folgt unserem Link, um das Angebot kennenzulernen. Weitere Infos auf der Aktionsseite. Einen Gutscheincode benötigt ihr nicht.

Abgelaufen
PicturePeople Logo
abgelaufen am: 14.02.25

Valentinstags-Special 2025

Folgt unserem Link, um das Angebot kennenzulernen. Weitere Infos auf der Aktionsseite. Einen Gutscheincode benötigt ihr nicht.

Abgelaufen
PicturePeople Logo
abgelaufen am: 30.04.24

Paar Fotoshooting Aktion

Einfach den Code beim Bestellen angeben Der Rabatt wird dann automatisch abgezogen

Gutschein Alarm

Wir schicken dir eine E-Mail, wenn es einen neuen
PicturePeople Gutscheincode gibt!

*

Mit der Eintragung deiner E-Mail Adresse akzeptierst du unsere Datenschutzbestimmungen. Geschützt durch reCaptcha Datenschutzerklärung - Nutzungsbedingungen