/
githubmirror
/
angular
Обзор
Документация
Войти
/
githubmirror
/
angular
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
packages/common/http/src/provider.ts
339 строк
11 KB
Jaime Burgos
fix(http): run root interceptors in the terminal request chain
31 июл 2026, 18:32
Не верифицирован
31 июл 2026, 18:32
bb78286
Код
Авторство
О чём код?
/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ import { EnvironmentProviders, inject, InjectionToken, makeEnvironmentProviders, Provider, } from '@angular/core'; import {HttpBackend, HttpHandler, HttpInterceptorHandler} from './backend'; import {HttpClient} from './client'; import {FetchBackend} from './fetch'; import {HTTP_INTERCEPTOR_FNS, HttpInterceptorFn, legacyInterceptorFnFactory} from './interceptor'; import { jsonpCallbackContext, JsonpCallbackContext, JsonpClientBackend, jsonpInterceptorFn, } from './jsonp'; import {HttpXhrBackend} from './xhr'; import {XSRF_COOKIE_NAME, XSRF_ENABLED, XSRF_HEADER_NAME, xsrfInterceptorFn} from './xsrf'; /** * Identifies a particular kind of `HttpFeature`. * * @publicApi */ export enum HttpFeatureKind { Interceptors, LegacyInterceptors, CustomXsrfConfiguration, NoXsrfProtection, JsonpSupport, RequestsMadeViaParent, Fetch, Xhr, } /** * A feature for use when configuring `provideHttpClient`. * * @publicApi */ export interface HttpFeature<KindT extends HttpFeatureKind> { ɵkind: KindT; ɵproviders: Provider[]; } function makeHttpFeature<KindT extends HttpFeatureKind>( kind: KindT, providers: Provider[], ): HttpFeature<KindT> { return { ɵkind: kind, ɵproviders: providers, }; } /** * Configures Angular's `HttpClient` service to be available for injection. * * The `HttpClient` service is provided in the root by default. * * By default, `HttpClient` will be configured for injection with its default options for XSRF * protection of outgoing requests. Additional configuration options can be provided by passing * feature functions to `provideHttpClient`. For example, HTTP interceptors can be added using the * `withInterceptors(...)` feature. * * <div class="docs-alert docs-alert-helpful"> * * By default, `HttpClient` uses the * [`fetch` API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) to make requests. * This is strongly recommended for applications that use * Server-Side Rendering for better performance and compatibility. * To use the `XMLHttpRequest` API instead, add the {@link withXhr} feature: * * ```ts * provideHttpClient(withXhr()); * ``` * * </div> * * @see [HTTP Client](guide/http/setup) * @see {@link withInterceptors} * @see {@link withInterceptorsFromDi} * @see {@link withXsrfConfiguration} * @see {@link withNoXsrfProtection} * @see {@link withJsonpSupport} * @see {@link withRequestsMadeViaParent} * @see {@link withXhr} */ export function provideHttpClient( ...features: HttpFeature<HttpFeatureKind>[] ): EnvironmentProviders { if (ngDevMode) { const featureKinds = new Set(features.map((f) => f.ɵkind)); if ( featureKinds.has(HttpFeatureKind.NoXsrfProtection) && featureKinds.has(HttpFeatureKind.CustomXsrfConfiguration) ) { throw new Error( `Configuration error: found both withXsrfConfiguration() and withNoXsrfProtection() in the same call to provideHttpClient(), which is a contradiction.`, ); } const hasBackendOverride = featureKinds.has(HttpFeatureKind.Fetch) || featureKinds.has(HttpFeatureKind.Xhr); if (featureKinds.has(HttpFeatureKind.RequestsMadeViaParent) && hasBackendOverride) { throw new Error( `Configuration error: withRequestsMadeViaParent() cannot be combined with withFetch() or withXhr() in the same call to provideHttpClient().`, ); } } const providers: Provider[] = [ HttpClient, FetchBackend, HttpInterceptorHandler, {provide: HttpHandler, useExisting: HttpInterceptorHandler}, { provide: HttpBackend, useFactory: () => { return inject(FetchBackend); }, }, { provide: HTTP_INTERCEPTOR_FNS, useValue: xsrfInterceptorFn, multi: true, }, ]; for (const feature of features) { providers.push(...feature.ɵproviders); } return makeEnvironmentProviders(providers); } /** * Adds one or more functional-style HTTP interceptors to the configuration of the `HttpClient` * instance. * * @see {@link HttpInterceptorFn} * @see {@link provideHttpClient} * @publicApi */ export function withInterceptors( interceptorFns: HttpInterceptorFn[], ): HttpFeature<HttpFeatureKind.Interceptors> { return makeHttpFeature( HttpFeatureKind.Interceptors, interceptorFns.map((interceptorFn) => { return { provide: HTTP_INTERCEPTOR_FNS, useValue: interceptorFn, multi: true, }; }), ); } const LEGACY_INTERCEPTOR_FN = new InjectionToken<HttpInterceptorFn>( typeof ngDevMode !== 'undefined' && ngDevMode ? 'LEGACY_INTERCEPTOR_FN' : '', ); /** * Includes class-based interceptors configured using a multi-provider in the current injector into * the configured `HttpClient` instance. * * Prefer `withInterceptors` and functional interceptors instead, as support for DI-provided * interceptors may be phased out in a later release. * * @see {@link HttpInterceptor} * @see {@link HTTP_INTERCEPTORS} * @see {@link provideHttpClient} */ export function withInterceptorsFromDi(): HttpFeature<HttpFeatureKind.LegacyInterceptors> { // Note: the legacy interceptor function is provided here via an intermediate token // (`LEGACY_INTERCEPTOR_FN`), using a pattern which guarantees that if these providers are // included multiple times, all of the multi-provider entries will have the same instance of the // interceptor function. That way, the `HttpINterceptorHandler` will dedup them and legacy // interceptors will not run multiple times. return makeHttpFeature(HttpFeatureKind.LegacyInterceptors, [ { provide: LEGACY_INTERCEPTOR_FN, useFactory: legacyInterceptorFnFactory, }, { provide: HTTP_INTERCEPTOR_FNS, useExisting: LEGACY_INTERCEPTOR_FN, multi: true, }, ]); } /** * Customizes the XSRF protection for the configuration of the current `HttpClient` instance. * * This feature is incompatible with the `withNoXsrfProtection` feature. * * @see {@link provideHttpClient} */ export function withXsrfConfiguration({ cookieName, headerName, }: { cookieName?: string; headerName?: string; }): HttpFeature<HttpFeatureKind.CustomXsrfConfiguration> { const providers: Provider[] = []; if (cookieName !== undefined) { providers.push({provide: XSRF_COOKIE_NAME, useValue: cookieName}); } if (headerName !== undefined) { providers.push({provide: XSRF_HEADER_NAME, useValue: headerName}); } return makeHttpFeature(HttpFeatureKind.CustomXsrfConfiguration, providers); } /** * Disables XSRF protection in the configuration of the current `HttpClient` instance. * * This feature is incompatible with the `withXsrfConfiguration` feature. * * @see {@link provideHttpClient} */ export function withNoXsrfProtection(): HttpFeature<HttpFeatureKind.NoXsrfProtection> { return makeHttpFeature(HttpFeatureKind.NoXsrfProtection, [ { provide: XSRF_ENABLED, useValue: false, }, ]); } /** * Add JSONP support to the configuration of the current `HttpClient` instance. * * @see {@link provideHttpClient} * @deprecated 22.1 JSONP is deprecated as it can cause XSS vulnerabilities. Use standard HTTP requests instead. Intent to remove in future versions of Angular. */ export function withJsonpSupport(): HttpFeature<HttpFeatureKind.JsonpSupport> { return makeHttpFeature(HttpFeatureKind.JsonpSupport, [ JsonpClientBackend, {provide: JsonpCallbackContext, useFactory: jsonpCallbackContext}, {provide: HTTP_INTERCEPTOR_FNS, useValue: jsonpInterceptorFn, multi: true}, ]); } /** * Configures the current `HttpClient` instance to make requests via the parent injector's * `HttpClient` instead of directly. * * By default, `provideHttpClient` configures `HttpClient` in its injector to be an independent * instance. For example, even if `HttpClient` is configured in the parent injector with * one or more interceptors, they will not intercept requests made via this instance. * * With this option enabled, once the request has passed through the current injector's * interceptors, it will be delegated to the parent injector's `HttpClient` chain instead of * dispatched directly, and interceptors in the parent configuration will be applied to the request. * * If there are several `HttpClient` instances in the injector hierarchy, it's possible for * `withRequestsMadeViaParent` to be used at multiple levels, which will cause the request to * "bubble up" until either reaching the root level or an `HttpClient` which was not configured with * this option. * * This feature cannot be combined with `withFetch` or `withXhr` in the same * `provideHttpClient()` call. * * @see [HTTP client setup](guide/http/setup#withrequestsmadeviaparent) * @see {@link provideHttpClient} * @publicApi 19.0 */ export function withRequestsMadeViaParent(): HttpFeature<HttpFeatureKind.RequestsMadeViaParent> { return makeHttpFeature(HttpFeatureKind.RequestsMadeViaParent, [ { provide: HttpBackend, useFactory: () => { const handlerFromParent = inject(HttpHandler, {skipSelf: true, optional: true}); if (ngDevMode && handlerFromParent === null) { throw new Error( 'withRequestsMadeViaParent() can only be used when the parent injector also configures HttpClient', ); } return handlerFromParent; }, }, ]); } /** * Configures the current `HttpClient` instance to make requests using the fetch API. * * Note: The Fetch API doesn't support progress report on uploads. * * @see [Advanced fetch Options](guide/http/making-requests#advanced-fetch-options) * * @publicApi * @deprecated `withFetch` is not required anymore. `FetchBackend` is the default `HttpBackend`. */ export function withFetch(): HttpFeature<HttpFeatureKind.Fetch> { return makeHttpFeature(HttpFeatureKind.Fetch, [ FetchBackend, {provide: HttpBackend, useExisting: FetchBackend}, ]); } /** * Configures the current `HttpClient` instance to make requests using the Xhr API. * * Use this feature if you want to report progress on uploads as the Xhr API supports it. * * <div class="docs-alert docs-alert-critical"> * * Do not use {@link withXhr} in server-side rendering (SSR) environments. XHR support on the * server is **deprecated** and is intended to be removed in Angular 23 because the underlying `xhr2` * library does not safely handle redirects (e.g. it can forward `Authorization` headers on * cross-origin redirects and is susceptible to denial-of-service via redirect loops). * * </div> * * @see {@link provideHttpClient} * @publicApi */ export function withXhr(): HttpFeature<HttpFeatureKind.Xhr> { return makeHttpFeature(HttpFeatureKind.Xhr, [ HttpXhrBackend, {provide: HttpBackend, useExisting: HttpXhrBackend}, ]); }