Backend system supporting XMLHttpRequest and JSONP with XSRF protection and connection management. Provides pluggable backend architecture for different HTTP transport mechanisms.
Abstract classes defining the connection interface for HTTP operations.
/**
* Abstract base class for HTTP connections
* Defines the interface for HTTP connection implementations
*/
abstract class Connection {
/** Current state of the connection */
readyState: ReadyState;
/** The HTTP request associated with this connection */
request: Request;
/** Observable stream of the HTTP response */
response: Observable<Response>;
}
/**
* Abstract factory for creating HTTP connections
* Provides pluggable backend architecture
*/
abstract class ConnectionBackend {
/**
* Creates a new connection for the given request
* @param request - HTTP request to create connection for
* @returns Connection instance for handling the request
*/
abstract createConnection(request: any): Connection;
}Backend implementation using XMLHttpRequest for standard HTTP operations.
/**
* Factory for creating XMLHttpRequest instances
* Injectable service for browser XMLHttpRequest creation
*/
class BrowserXhr {
/**
* Creates a new XMLHttpRequest instance
* @returns New XMLHttpRequest object
*/
build(): XMLHttpRequest;
}
/**
* XMLHttpRequest-based HTTP connection implementation
* Handles XMLHttpRequest lifecycle and response processing
*/
class XHRConnection implements Connection {
/**
* Creates a new XHR connection
* @param req - HTTP request to execute
* @param browserXHR - XMLHttpRequest factory
* @param baseResponseOptions - Default response options
*/
constructor(req: Request, browserXHR: BrowserXhr, baseResponseOptions?: ResponseOptions);
/** HTTP request for this connection */
request: Request;
/** Observable response stream */
response: Observable<Response>;
/** Current connection state */
readyState: ReadyState;
/**
* Sets detected content type on request
* @param req - Request to modify
* @param _xhr - XMLHttpRequest instance
*/
setDetectedContentType(req: any, _xhr: any): void;
}
/**
* Backend that creates XMLHttpRequest connections
* Injectable service for XMLHttpRequest-based HTTP operations
*/
class XHRBackend implements ConnectionBackend {
/**
* Creates a new XHR backend
* @param _browserXHR - XMLHttpRequest factory
* @param _baseResponseOptions - Default response options
* @param _xsrfStrategy - XSRF protection strategy
*/
constructor(
private _browserXHR: BrowserXhr,
private _baseResponseOptions: ResponseOptions,
private _xsrfStrategy: XSRFStrategy
);
/**
* Creates a new XMLHttpRequest connection
* @param request - HTTP request to execute
* @returns XHRConnection instance
*/
createConnection(request: Request): XHRConnection;
}Usage Examples:
import { XHRBackend, BrowserXhr, BaseResponseOptions, CookieXSRFStrategy } from '@angular/http';
class XHRBackendService {
// Create XHR backend with dependencies
createXHRBackend(): XHRBackend {
const browserXhr = new BrowserXhr();
const responseOptions = new BaseResponseOptions();
const xsrfStrategy = new CookieXSRFStrategy();
return new XHRBackend(browserXhr, responseOptions, xsrfStrategy);
}
// Make request using XHR backend
makeXHRRequest(): Observable<Response> {
const backend = this.createXHRBackend();
const request = new Request({
method: RequestMethod.Get,
url: '/api/data',
headers: new Headers({ 'Accept': 'application/json' })
});
const connection = backend.createConnection(request);
return connection.response;
}
}Backend implementation using JSONP (JSON with Padding) for cross-domain requests.
JSONP Constants:
/** Global namespace for JSONP callbacks */
const JSONP_HOME: string; // '__ng_jsonp__'/**
* DOM manipulation service for JSONP requests
* Handles script injection and cleanup for JSONP operations
*/
class BrowserJsonp {
constructor();
/**
* Creates a script element for JSONP request
* @param url - URL for the JSONP request
* @returns Script element configured for JSONP
*/
build(url: string): HTMLScriptElement;
/**
* Generates next unique request ID
* @returns Unique string identifier for request
*/
nextRequestID(): string;
/**
* Gets callback function name for request ID
* @param id - Request identifier
* @returns Callback function name
*/
requestCallback(id: string): string;
/**
* Exposes connection in global scope for callback
* @param id - Request identifier
* @param connection - Connection to expose
*/
exposeConnection(id: string, connection: any): void;
/**
* Removes connection from global scope
* @param id - Request identifier
*/
removeConnection(id: string): void;
/**
* Appends script element to DOM to initiate request
* @param node - Script element to append
*/
send(node: HTMLScriptElement): void;
/**
* Removes script element from DOM
* @param node - Script element to remove
*/
cleanup(node: HTMLScriptElement): void;
}
/**
* JSONP connection implementation using script injection
* Handles JSONP request lifecycle and response processing
*/
class JSONPConnection implements Connection {
/**
* Creates a new JSONP connection
* @param req - HTTP request to execute
* @param _dom - DOM manipulation service
* @param baseResponseOptions - Default response options
*/
constructor(req: Request, private _dom: BrowserJsonp, private baseResponseOptions?: ResponseOptions);
/** Current connection state */
readyState: ReadyState;
/** HTTP request for this connection */
request: Request;
/** Observable response stream */
response: Observable<Response>;
/**
* Handles completion of JSONP request
* @param data - Response data from JSONP callback
*/
finished(data?: any): void;
}
/**
* Backend that creates JSONP connections
* Injectable service for JSONP-based HTTP operations
*/
class JSONPBackend extends ConnectionBackend {
/**
* Creates a new JSONP backend
* @param _browserJSONP - DOM manipulation service
* @param _baseResponseOptions - Default response options
*/
constructor(private _browserJSONP: BrowserJsonp, private _baseResponseOptions: ResponseOptions);
/**
* Creates a new JSONP connection
* @param request - HTTP request to execute
* @returns JSONPConnection instance
*/
createConnection(request: Request): JSONPConnection;
}Usage Examples:
import { JSONPBackend, BrowserJsonp, BaseResponseOptions } from '@angular/http';
class JSONPBackendService {
// Create JSONP backend
createJSONPBackend(): JSONPBackend {
const browserJsonp = new BrowserJsonp();
const responseOptions = new BaseResponseOptions();
return new JSONPBackend(browserJsonp, responseOptions);
}
// Make JSONP request
makeJSONPRequest(): Observable<Response> {
const backend = this.createJSONPBackend();
const request = new Request({
method: RequestMethod.Get,
url: 'https://api.external.com/data?callback=JSONP_CALLBACK'
});
const connection = backend.createConnection(request);
return connection.response;
}
// Handle JSONP with error handling
safeJSONPRequest(url: string): Observable<any> {
const backend = this.createJSONPBackend();
const request = new Request({
method: RequestMethod.Get,
url: url
});
const connection = backend.createConnection(request);
return connection.response.pipe(
map(response => response.json()),
timeout(10000), // 10 second timeout
catchError(error => {
console.error('JSONP request failed:', error);
return throwError('JSONP request timeout or failed');
})
);
}
}Cross-Site Request Forgery protection strategies for secure HTTP operations.
/**
* Abstract base class for XSRF protection strategies
* Defines interface for configuring XSRF protection on requests
*/
abstract class XSRFStrategy {
/**
* Configures XSRF protection on HTTP request
* @param req - Request to configure with XSRF protection
*/
abstract configureRequest(req: Request): void;
}
/**
* Cookie-based XSRF protection strategy
* Reads XSRF token from cookie and adds it to request headers
*/
class CookieXSRFStrategy implements XSRFStrategy {
/**
* Creates cookie-based XSRF strategy
* @param _cookieName - Name of cookie containing XSRF token (default: 'XSRF-TOKEN')
* @param _headerName - Name of header to add token to (default: 'X-XSRF-TOKEN')
*/
constructor(private _cookieName: string = 'XSRF-TOKEN', private _headerName: string = 'X-XSRF-TOKEN');
/**
* Configures request with XSRF token from cookie
* @param req - Request to configure
*/
configureRequest(req: Request): void;
}Usage Examples:
import { CookieXSRFStrategy, XSRFStrategy } from '@angular/http';
class XSRFService {
// Create default XSRF strategy
createDefaultXSRFStrategy(): CookieXSRFStrategy {
return new CookieXSRFStrategy();
}
// Create custom XSRF strategy
createCustomXSRFStrategy(): CookieXSRFStrategy {
return new CookieXSRFStrategy('MY_XSRF_TOKEN', 'X-MY-XSRF-TOKEN');
}
// Apply XSRF protection to request
protectRequest(request: Request): void {
const xsrfStrategy = this.createDefaultXSRFStrategy();
xsrfStrategy.configureRequest(request);
}
}
// Custom XSRF strategy implementation
class CustomXSRFStrategy implements XSRFStrategy {
configureRequest(req: Request): void {
// Custom XSRF token logic
const token = this.getXSRFToken();
if (token) {
req.headers.set('X-CSRF-Token', token);
}
}
private getXSRFToken(): string | null {
// Custom token retrieval logic
return localStorage.getItem('csrfToken');
}
}import { ConnectionBackend, Connection, Request, Response } from '@angular/http';
import { Observable } from 'rxjs';
// Custom backend for special requirements
class CustomBackend extends ConnectionBackend {
constructor(private config: any) {
super();
}
createConnection(request: Request): Connection {
return new CustomConnection(request, this.config);
}
}
class CustomConnection implements Connection {
readyState: ReadyState;
request: Request;
response: Observable<Response>;
constructor(request: Request, private config: any) {
this.request = request;
this.readyState = ReadyState.Unsent;
this.response = this.createResponse();
}
private createResponse(): Observable<Response> {
// Custom response creation logic
return new Observable(observer => {
// Custom HTTP handling logic
this.performCustomRequest()
.then(result => {
const response = new Response({
body: result,
status: 200,
statusText: 'OK',
url: this.request.url
});
observer.next(response);
observer.complete();
})
.catch(error => {
observer.error(error);
});
});
}
private async performCustomRequest(): Promise<any> {
// Custom request implementation
return fetch(this.request.url)
.then(response => response.json());
}
}import { Injectable, NgModule } from '@angular/core';
import { Http, ConnectionBackend, RequestOptions } from '@angular/http';
// Custom HTTP factory with backend selection
export function httpFactory(
xhrBackend: XHRBackend,
jsonpBackend: JSONPBackend,
requestOptions: RequestOptions
): Http {
// Choose backend based on environment or configuration
const backend = shouldUseJSONP() ? jsonpBackend : xhrBackend;
return new Http(backend, requestOptions);
}
function shouldUseJSONP(): boolean {
// Logic to determine if JSONP should be used
return window.location.protocol === 'file:';
}
@NgModule({
providers: [
{
provide: Http,
useFactory: httpFactory,
deps: [XHRBackend, JSONPBackend, RequestOptions]
}
]
})
export class CustomHttpModule {}class ConnectionStateService {
private connections: Map<string, Connection> = new Map();
trackConnection(id: string, connection: Connection): void {
this.connections.set(id, connection);
// Monitor connection state
this.monitorConnection(id, connection);
}
private monitorConnection(id: string, connection: Connection): void {
// Log state changes
console.log(`Connection ${id} state:`, ReadyState[connection.readyState]);
connection.response.subscribe({
next: response => {
console.log(`Connection ${id} received response:`, response.status);
},
error: error => {
console.error(`Connection ${id} error:`, error);
this.connections.delete(id);
},
complete: () => {
console.log(`Connection ${id} completed`);
this.connections.delete(id);
}
});
}
getActiveConnections(): Connection[] {
return Array.from(this.connections.values())
.filter(conn => conn.readyState !== ReadyState.Done);
}
cancelAllConnections(): void {
this.connections.forEach((connection, id) => {
if (connection.readyState !== ReadyState.Done) {
// Implementation would need cancellation logic
console.log(`Cancelling connection ${id}`);
}
});
this.connections.clear();
}
}class ErrorHandlingBackend extends ConnectionBackend {
constructor(private wrappedBackend: ConnectionBackend) {
super();
}
createConnection(request: Request): Connection {
const originalConnection = this.wrappedBackend.createConnection(request);
return new ErrorHandlingConnection(originalConnection);
}
}
class ErrorHandlingConnection implements Connection {
readyState: ReadyState;
request: Request;
response: Observable<Response>;
constructor(private originalConnection: Connection) {
this.readyState = originalConnection.readyState;
this.request = originalConnection.request;
this.response = originalConnection.response.pipe(
retry(3), // Retry failed requests
catchError(this.handleError),
timeout(30000) // 30 second timeout
);
}
private handleError = (error: any): Observable<Response> => {
console.error('HTTP request failed:', error);
// Create error response
const errorResponse = new Response({
body: JSON.stringify({ error: 'Request failed' }),
status: error.status || 500,
statusText: error.statusText || 'Internal Server Error',
url: this.request.url
});
return Observable.of(errorResponse);
}
}