Aktuelle PicturePeople Gutscheine & Deals

Leider haben wir aktuell keine PicturePeople Gutscheine oder Angebote verfügbar. Wenn Sie den Gutschein-Alarm aktivieren informieren wir Sie sobald wir neue Gutscheine oder Angebote finden.

Diese Gutscheine könnten dir auch gefallen

Geekom Logo
Gültig bis 31. Dezember 2050

40,00€ Rabatt

Gilt auf FUN9 und FUN11 Einfach den Code beim Bestellen angeben Der Rabatt wird dann automatisch abgezogen

XXXXXXUN40 Gutschein anzeigen
Perform Better Logo
Gültig bis 31. Dezember 2026

10,00 Prozent Rabatt

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

XXXXPB24 Gutschein anzeigen
TummyTox Logo
Gültig bis 11. Januar 2030

15,00 Prozent Rabatt

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

XXXXXRDEN Gutschein anzeigen
Parfumdreams Logo
Gültig bis 04. April 2030

5,00€ Rabatt


Gilt nur für Neukunden.

XXXX4HV5 Gutschein anzeigen
SharkClean Logo
Gültig bis 21. Juni 2028

200,00€ Rabatt

Gilt auf CZ-Serie Staubsauger Einfach den Code beim Bestellen angeben Der Rabatt wird dann automatisch abgezogen

XXZ200 Gutschein anzeigen
AfB Logo
Gültig bis 14. August 2038

15% Rabatt auf Fujitsu Produkte

15,00% Rabatt auf alle Fujitsu Notebooks, Tablets, Monitore, PCs und Workstations im afbshop.de. Top A+ Ware Bester Internetpreis bei idealo Vorführmodelle 3-5 Wochen alt Originalverpackt Inkl. Fujitsu Werksgarantie Der Gutschein kann mehrmals pro Kunde eingelöst werden, ist zeitlich unbegrenzt und ohne Mindestbestellwert gültig. Hinweis: Gutscheincodes sind nicht einlösbar auf bereits reduzierte Ware, Aktions-Produkte, LiveShopping Angebote, Neuware und Zubehör. Gutscheincodes sind nicht kombinierbar mit anderen Gutscheinen, Rabatten oder Partnercodes.

XXXXXsu15 Gutschein anzeigen
Fritz Berger Logo
Gültig bis auf Widerruf

30,00 Prozent Rabatt

Gilt auf Schuhe

XXXXNT30 Gutschein anzeigen
Superestudio Logo
Gültig bis auf Widerruf

30€ Rabatt


350 Euro Mindestbestellwert

XXXXXXXAS30 Gutschein anzeigen
sportlaedchen.de Logo
Gültig bis 31. Dezember 2027

5,00€ Gutschein

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

SPL5 Gutschein anzeigen
Les Lunes Logo
Gültig bis 05. März 2027

Bis zu 25,00 Prozent Rabatt

XXXXXXXXXXXXXie25 Gutschein anzeigen

Abgelaufene PicturePeople Gutscheine & Deals

Abgelaufen
Les Lunes Logo
abgelaufen am: 31.10.25

Gratis Mini-Shooting

Abgelaufen
Les Lunes Logo
abgelaufen am: 31.10.25

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的取消功能。

Abgelaufen
Les Lunes Logo
abgelaufen am: 11.05.25

Muttertag-Special

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

Abgelaufen
Les Lunes 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
Les Lunes 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.

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