99import {
1010 EnvironmentInjector ,
1111 inject ,
12- Injectable ,
1312 InjectionToken ,
1413 runInInjectionContext ,
15- ɵConsole as Console ,
16- ɵformatRuntimeError as formatRuntimeError ,
1714 PendingTasks ,
1815} from '@angular/core' ;
1916import { Observable } from 'rxjs' ;
2017import { finalize } from 'rxjs/operators' ;
2118
22- import { HttpBackend , HttpHandler } from './backend' ;
23- import { RuntimeErrorCode } from './errors' ;
24- import { FetchBackend } from './fetch' ;
19+ import type { HttpHandler } from './backend' ;
20+
2521import { HttpRequest } from './request' ;
2622import { HttpEvent } from './response' ;
2723
@@ -144,12 +140,12 @@ export type HttpInterceptorFn = (
144140 * `HttpInterceptorFn`, which is a useful abstraction for including different kinds of interceptors
145141 * (e.g. legacy class-based interceptors) in the same chain.
146142 */
147- type ChainedInterceptorFn < RequestT > = (
143+ export type ChainedInterceptorFn < RequestT > = (
148144 req : HttpRequest < RequestT > ,
149145 finalHandlerFn : HttpHandlerFn ,
150146) => Observable < HttpEvent < RequestT > > ;
151147
152- function interceptorChainEndFn (
148+ export function interceptorChainEndFn (
153149 req : HttpRequest < any > ,
154150 finalHandlerFn : HttpHandlerFn ,
155151) : Observable < HttpEvent < any > > {
@@ -160,7 +156,7 @@ function interceptorChainEndFn(
160156 * Constructs a `ChainedInterceptorFn` which adapts a legacy `HttpInterceptor` to the
161157 * `ChainedInterceptorFn` interface.
162158 */
163- function adaptLegacyInterceptorToChain (
159+ export function adaptLegacyInterceptorToChain (
164160 chainTailFn : ChainedInterceptorFn < any > ,
165161 interceptor : HttpInterceptor ,
166162) : ChainedInterceptorFn < any > {
@@ -174,7 +170,7 @@ function adaptLegacyInterceptorToChain(
174170 * Constructs a `ChainedInterceptorFn` which wraps and invokes a functional interceptor in the given
175171 * injector.
176172 */
177- function chainedInterceptorFn (
173+ export function chainedInterceptorFn (
178174 chainTailFn : ChainedInterceptorFn < unknown > ,
179175 interceptorFn : HttpInterceptorFn ,
180176 injector : EnvironmentInjector ,
@@ -202,6 +198,7 @@ export const HTTP_INTERCEPTORS = new InjectionToken<readonly HttpInterceptor[]>(
202198 */
203199export const HTTP_INTERCEPTOR_FNS = new InjectionToken < readonly HttpInterceptorFn [ ] > (
204200 ngDevMode ? 'HTTP_INTERCEPTOR_FNS' : '' ,
201+ { factory : ( ) => [ ] } ,
205202) ;
206203
207204/**
@@ -249,89 +246,3 @@ export function legacyInterceptorFnFactory(): HttpInterceptorFn {
249246 }
250247 } ;
251248}
252-
253- let fetchBackendWarningDisplayed = false ;
254-
255- /** Internal function to reset the flag in tests */
256- export function resetFetchBackendWarningFlag ( ) {
257- fetchBackendWarningDisplayed = false ;
258- }
259-
260- @Injectable ( )
261- export class HttpInterceptorHandler extends HttpHandler {
262- private chain : ChainedInterceptorFn < unknown > | null = null ;
263- private readonly pendingTasks = inject ( PendingTasks ) ;
264- private readonly contributeToStability = inject ( REQUESTS_CONTRIBUTE_TO_STABILITY ) ;
265-
266- constructor (
267- private backend : HttpBackend ,
268- private injector : EnvironmentInjector ,
269- ) {
270- super ( ) ;
271-
272- // We strongly recommend using fetch backend for HTTP calls when SSR is used
273- // for an application. The logic below checks if that's the case and produces
274- // a warning otherwise.
275- if ( ( typeof ngDevMode === 'undefined' || ngDevMode ) && ! fetchBackendWarningDisplayed ) {
276- // This flag is necessary because provideHttpClientTesting() overrides the backend
277- // even if `withFetch()` is used within the test. When the testing HTTP backend is provided,
278- // no HTTP calls are actually performed during the test, so producing a warning would be
279- // misleading.
280- const isTestingBackend = ( this . backend as any ) . isTestingBackend ;
281-
282- if (
283- typeof ngServerMode !== 'undefined' &&
284- ngServerMode &&
285- ! ( this . backend instanceof FetchBackend ) &&
286- ! isTestingBackend
287- ) {
288- fetchBackendWarningDisplayed = true ;
289- injector
290- . get ( Console )
291- . warn (
292- formatRuntimeError (
293- RuntimeErrorCode . NOT_USING_FETCH_BACKEND_IN_SSR ,
294- 'Angular detected that `HttpClient` is not configured ' +
295- "to use `fetch` APIs. It's strongly recommended to " +
296- 'enable `fetch` for applications that use Server-Side Rendering ' +
297- 'for better performance and compatibility. ' +
298- 'To enable `fetch`, add the `withFetch()` to the `provideHttpClient()` ' +
299- 'call at the root of the application.' ,
300- ) ,
301- ) ;
302- }
303- }
304- }
305-
306- override handle ( initialRequest : HttpRequest < any > ) : Observable < HttpEvent < any > > {
307- if ( this . chain === null ) {
308- const dedupedInterceptorFns = Array . from (
309- new Set ( [
310- ...this . injector . get ( HTTP_INTERCEPTOR_FNS ) ,
311- ...this . injector . get ( HTTP_ROOT_INTERCEPTOR_FNS , [ ] ) ,
312- ] ) ,
313- ) ;
314-
315- // Note: interceptors are wrapped right-to-left so that final execution order is
316- // left-to-right. That is, if `dedupedInterceptorFns` is the array `[a, b, c]`, we want to
317- // produce a chain that is conceptually `c(b(a(end)))`, which we build from the inside
318- // out.
319- this . chain = dedupedInterceptorFns . reduceRight (
320- ( nextSequencedFn , interceptorFn ) =>
321- chainedInterceptorFn ( nextSequencedFn , interceptorFn , this . injector ) ,
322- interceptorChainEndFn as ChainedInterceptorFn < unknown > ,
323- ) ;
324- }
325-
326- if ( this . contributeToStability ) {
327- const removeTask = this . pendingTasks . add ( ) ;
328- return this . chain ( initialRequest , ( downstreamRequest ) =>
329- this . backend . handle ( downstreamRequest ) ,
330- ) . pipe ( finalize ( removeTask ) ) ;
331- } else {
332- return this . chain ( initialRequest , ( downstreamRequest ) =>
333- this . backend . handle ( downstreamRequest ) ,
334- ) ;
335- }
336- }
337- }
0 commit comments