fix(platform-browser): configure `XhrFactory` to use `BrowserXhr` (#41313)

With this change we move `XhrFactory` to the root entrypoint of `@angular/commmon`, this is needed so that we can configure `XhrFactory` DI token at a platform level, and not add a dependency  between `@angular/platform-browser` and `@angular/common/http`.

Currently, when using `HttpClientModule` in a child module on the server, `ReferenceError: XMLHttpRequest is not defined` is being thrown because the child module has its own Injector and causes `XhrFactory` provider to be configured to use `BrowserXhr`.
Therefore, we should configure the `XhrFactory` at a platform level similar to other Browser specific providers.

BREAKING CHANGE:

`XhrFactory` has been moved from `@angular/common/http` to `@angular/common`.

**Before**
```ts
import {XhrFactory} from '@angular/common/http';
```

**After**
```ts
import {XhrFactory} from '@angular/common';
```

Closes #41311

PR Close #41313
This commit is contained in:
Alan Agius 2021-03-23 10:28:54 +01:00 committed by Alex Rickabaugh
parent b61c009c54
commit e0028e5741
20 changed files with 74 additions and 50 deletions

View File

@ -433,3 +433,7 @@ export declare enum WeekDay {
Friday = 5,
Saturday = 6
}
export declare abstract class XhrFactory {
abstract build(): XMLHttpRequest;
}

View File

@ -1947,7 +1947,3 @@ export declare class JsonpInterceptor {
constructor(jsonp: JsonpClientBackend);
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>;
}
export declare abstract class XhrFactory {
abstract build(): XMLHttpRequest;
}

View File

@ -21,7 +21,7 @@
"master": {
"uncompressed": {
"runtime-es2015": 3153,
"main-es2015": 437810,
"main-es2015": 437306,
"polyfills-es2015": 52493
}
}

View File

@ -21,7 +21,7 @@
"master": {
"uncompressed": {
"runtime-es2015": 1485,
"main-es2015": 144151,
"main-es2015": 144579,
"polyfills-es2015": 36964
}
}
@ -39,7 +39,7 @@
"master": {
"uncompressed": {
"runtime-es2015": 2285,
"main-es2015": 240352,
"main-es2015": 240874,
"polyfills-es2015": 36975,
"5-es2015": 753
}

View File

@ -6,6 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
// TODO(alan-agius4): remove this export once migration has been done in Google3. (Should happen
// prior to V12 RC).
export {XhrFactory} from '@angular/common';
export {HttpBackend, HttpHandler} from './src/backend';
export {HttpClient} from './src/client';
export {HttpContext, HttpContextToken} from './src/context';
@ -16,5 +20,5 @@ export {HttpClientJsonpModule, HttpClientModule, HttpClientXsrfModule, HttpInter
export {HttpParameterCodec, HttpParams, HttpParamsOptions, HttpUrlEncodingCodec} from './src/params';
export {HttpRequest} from './src/request';
export {HttpDownloadProgressEvent, HttpErrorResponse, HttpEvent, HttpEventType, HttpHeaderResponse, HttpProgressEvent, HttpResponse, HttpResponseBase, HttpSentEvent, HttpStatusCode, HttpUploadProgressEvent, HttpUserEvent} from './src/response';
export {HttpXhrBackend, XhrFactory} from './src/xhr';
export {HttpXhrBackend} from './src/xhr';
export {HttpXsrfTokenExtractor} from './src/xsrf';

View File

@ -15,7 +15,7 @@ import {HTTP_INTERCEPTORS, HttpInterceptor, HttpInterceptorHandler, NoopIntercep
import {JsonpCallbackContext, JsonpClientBackend, JsonpInterceptor} from './jsonp';
import {HttpRequest} from './request';
import {HttpEvent} from './response';
import {BrowserXhr, HttpXhrBackend, XhrFactory} from './xhr';
import {HttpXhrBackend} from './xhr';
import {HttpXsrfCookieExtractor, HttpXsrfInterceptor, HttpXsrfTokenExtractor, XSRF_COOKIE_NAME, XSRF_HEADER_NAME} from './xsrf';
/**
@ -159,8 +159,6 @@ export class HttpClientXsrfModule {
{provide: HttpHandler, useClass: HttpInterceptingHandler},
HttpXhrBackend,
{provide: HttpBackend, useExisting: HttpXhrBackend},
BrowserXhr,
{provide: XhrFactory, useExisting: BrowserXhr},
],
})
export class HttpClientModule {

View File

@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {XhrFactory} from '@angular/common';
import {Injectable} from '@angular/core';
import {Observable, Observer} from 'rxjs';
@ -31,37 +32,6 @@ function getResponseUrl(xhr: any): string|null {
return null;
}
/**
* A wrapper around the `XMLHttpRequest` constructor.
*
* @publicApi
*/
export abstract class XhrFactory {
abstract build(): XMLHttpRequest;
}
/**
* A factory for `HttpXhrBackend` that uses the `XMLHttpRequest` browser API.
*
*/
@Injectable()
export class BrowserXhr implements XhrFactory {
constructor() {}
build(): any {
return <any>(new XMLHttpRequest());
}
}
/**
* Tracks a response from the server that does not yet have a body.
*/
interface PartialResponse {
headers: HttpHeaders;
status: number;
statusText: string;
url: string;
}
/**
* Uses `XMLHttpRequest` to send requests to a backend server.
* @see `HttpHandler`

View File

@ -16,6 +16,7 @@ ts_library(
# Visible to //:saucelabs_unit_tests_poc target
visibility = ["//:__pkg__"],
deps = [
"//packages/common",
"//packages/common/http",
"//packages/common/http/testing",
"//packages/core",

View File

@ -6,8 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {XhrFactory} from '@angular/common';
import {HttpHeaders} from '@angular/common/http/src/headers';
import {XhrFactory} from '@angular/common/http/src/xhr';
export class MockXhrFactory implements XhrFactory {
// TODO(issue/24571): remove '!'.

View File

@ -26,3 +26,4 @@ export {AsyncPipe, DatePipe, I18nPluralPipe, I18nSelectPipe, JsonPipe, LowerCase
export {PLATFORM_BROWSER_ID as ɵPLATFORM_BROWSER_ID, PLATFORM_SERVER_ID as ɵPLATFORM_SERVER_ID, PLATFORM_WORKER_APP_ID as ɵPLATFORM_WORKER_APP_ID, PLATFORM_WORKER_UI_ID as ɵPLATFORM_WORKER_UI_ID, isPlatformBrowser, isPlatformServer, isPlatformWorkerApp, isPlatformWorkerUi} from './platform_id';
export {VERSION} from './version';
export {ViewportScroller, NullViewportScroller as ɵNullViewportScroller} from './viewport_scroller';
export {XhrFactory} from './xhr';

View File

@ -0,0 +1,16 @@
/**
* @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.io/license
*/
/**
* A wrapper around the `XMLHttpRequest` constructor.
*
* @publicApi
*/
export abstract class XhrFactory {
abstract build(): XMLHttpRequest;
}

View File

@ -53,6 +53,9 @@
{
"name": "BrowserModule"
},
{
"name": "BrowserXhr"
},
{
"name": "BuiltInControlValueAccessor"
},

View File

@ -53,6 +53,9 @@
{
"name": "BrowserModule"
},
{
"name": "BrowserXhr"
},
{
"name": "BuiltInControlValueAccessor"
},

View File

@ -80,6 +80,9 @@
{
"name": "BrowserViewportScroller"
},
{
"name": "BrowserXhr"
},
{
"name": "CIRCULAR"
},

View File

@ -6,7 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {HttpBackend, HttpEvent, HttpHeaders, HttpParams, HttpRequest, HttpResponse, HttpXhrBackend, XhrFactory} from '@angular/common/http';
import {XhrFactory} from '@angular/common';
import {HttpBackend, HttpEvent, HttpHeaders, HttpParams, HttpRequest, HttpResponse, HttpXhrBackend} from '@angular/common/http';
import {Inject, Injectable, Optional} from '@angular/core';
import {Observable} from 'rxjs';
import {map} from 'rxjs/operators';

View File

@ -6,7 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {HttpBackend, XhrFactory} from '@angular/common/http';
import {XhrFactory} from '@angular/common';
import {HttpBackend} from '@angular/common/http';
import {ModuleWithProviders, NgModule, Type} from '@angular/core';
import {HttpClientBackendService} from './http-client-backend-service';

View File

@ -6,7 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {HttpBackend, XhrFactory} from '@angular/common/http';
import {XhrFactory} from '@angular/common';
import {HttpBackend} from '@angular/common/http';
import {ModuleWithProviders, NgModule, Type} from '@angular/core';
import {httpClientInMemBackendServiceFactory} from './http-client-in-memory-web-api-module';

View File

@ -6,12 +6,13 @@
* found in the LICENSE file at https://angular.io/license
*/
import {CommonModule, DOCUMENT, ɵPLATFORM_BROWSER_ID as PLATFORM_BROWSER_ID} from '@angular/common';
import {APP_ID, ApplicationModule, createPlatformFactory, ErrorHandler, Inject, ModuleWithProviders, NgModule, NgZone, Optional, PLATFORM_ID, PLATFORM_INITIALIZER, platformCore, PlatformRef, RendererFactory2, Sanitizer, SkipSelf, StaticProvider, Testability, ɵConsole as Console, ɵINJECTOR_SCOPE as INJECTOR_SCOPE, ɵsetDocument} from '@angular/core';
import {CommonModule, DOCUMENT, XhrFactory, ɵPLATFORM_BROWSER_ID as PLATFORM_BROWSER_ID} from '@angular/common';
import {APP_ID, ApplicationModule, createPlatformFactory, ErrorHandler, Inject, ModuleWithProviders, NgModule, NgZone, Optional, PLATFORM_ID, PLATFORM_INITIALIZER, platformCore, PlatformRef, RendererFactory2, Sanitizer, SkipSelf, StaticProvider, Testability, ɵINJECTOR_SCOPE as INJECTOR_SCOPE, ɵsetDocument} from '@angular/core';
import {BrowserDomAdapter} from './browser/browser_adapter';
import {SERVER_TRANSITION_PROVIDERS, TRANSITION_ID} from './browser/server-transition';
import {BrowserGetTestability} from './browser/testability';
import {BrowserXhr} from './browser/xhr';
import {ELEMENT_PROBE_PROVIDERS} from './dom/debug/ng_probe';
import {DomRendererFactory2} from './dom/dom_renderer';
import {DomEventsPlugin} from './dom/events/dom_events';
@ -88,6 +89,7 @@ export const BROWSER_MODULE_PROVIDERS: StaticProvider[] = [
{provide: DomSharedStylesHost, useClass: DomSharedStylesHost, deps: [DOCUMENT]},
{provide: Testability, useClass: Testability, deps: [NgZone]},
{provide: EventManager, useClass: EventManager, deps: [EVENT_MANAGER_PLUGINS, NgZone]},
{provide: XhrFactory, useClass: BrowserXhr, deps: []},
ELEMENT_PROBE_PROVIDERS,
];

View File

@ -0,0 +1,20 @@
/**
* @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.io/license
*/
import {XhrFactory} from '@angular/common';
import {Injectable} from '@angular/core';
/**
* A factory for `HttpXhrBackend` that uses the `XMLHttpRequest` browser API.
*/
@Injectable()
export class BrowserXhr implements XhrFactory {
build(): XMLHttpRequest {
return new XMLHttpRequest();
}
}

View File

@ -11,8 +11,8 @@ import {INITIAL_CONFIG, PlatformConfig} from './tokens';
const xhr2: any = require('xhr2');
import {Injectable, Injector, Provider} from '@angular/core';
import {PlatformLocation} from '@angular/common';
import {HttpEvent, HttpRequest, HttpHandler, HttpBackend, XhrFactory, ɵHttpInterceptingHandler as HttpInterceptingHandler} from '@angular/common/http';
import {PlatformLocation, XhrFactory} from '@angular/common';
import {HttpEvent, HttpRequest, HttpHandler, HttpBackend, ɵHttpInterceptingHandler as HttpInterceptingHandler} from '@angular/common/http';
import {Observable, Observer, Subscription} from 'rxjs';
// @see https://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-01#URI-syntax