Necesito obtener la URL base completa (por ejemplo, http://localhost:5000 o https://productionserver.com ) de mi aplicación Angular 2 para poder pasarla a un servicio de terceros en el contexto de la aplicación. La ubicación de la aplicación varía dependiendo de si se trata de desarrollo, varios entornos de ensayo/prueba o producción, y me gustaría detectarla dinámicamente para no tener que mantener una lista codificada.
Se ha publicado una pregunta similar en el pasado, pero las respuestas (es decir, usar alguna versión de la propiedad window.location.hostname o window.location.origin) solo funcionan cuando el navegador procesa la aplicación angular2.
Me gustaría que mi aplicación funcione con Angular Universal, lo que significa que debe renderizarse en el lado del servidor donde no hay acceso a objetos DOM como window.location .
¿Alguna idea sobre cómo lograr esto? Como referencia, use asp.net core como back-end (usando la nueva plantilla angular predeterminada de dotnet ).
Tengo un poco de código de trabajo con angular 5 y angular universal
en server.ts reemplaza esto
app.engine('html', (_, options, callback) => { let engine = ngExpressEngine({ bootstrap: AppServerModuleNgFactory, providers: [ { provide: 'request', useFactory: () => options.req, deps: [] }, provideModuleMap(LAZY_MODULE_MAP) ] }); engine(_, options, callback); });y en el lado Angular puede obtener host con el siguiente código
export class AppComponent { constructor( private injector: Injector, @Inject(PLATFORM_ID) private platformId: Object ) { console.log('hi, we\'re here!'); if (isPlatformServer(this.platformId)) { let req = this.injector.get('request'); console.log("locales from crawlers: " + req.headers["accept-language"]); console.log("host: " + req.get('host')); console.log("headers: ", req.headers); } else { console.log('we\'re rendering from the browser, there is no request object.'); } } }Ahora estoy usando server.ts ngExpressEngine :
import { ngExpressEngine } from '@nguniversal/express-engine'; const {AppServerModuleNgFactory, LAZY_MODULE_MAP} = require('./dist/server/main.bundle'); const {provideModuleMap} = require('@nguniversal/module-map-ngfactory-loader'); app.engine('html', ngExpressEngine({ bootstrap: AppServerModuleNgFactory, providers: [ provideModuleMap(LAZY_MODULE_MAP) ] }));Y después de eso puedo usar en location.service.ts:
constructor(@Optional() @Inject(REQUEST) private request: any, @Optional() @Inject(RESPONSE) private response: any, @Inject(PLATFORM_ID) private platformId: Object) { if (isPlatformServer(this.platformId)) { console.log(this.request.get('host')); // host on the server } else { console.log(document.location.hostname); // host on the browser } }Descubrirá que todo el contenido proveniente de solicitudes Http no se procesará previamente: es porque Universal necesita URL absolutas.
Como su servidor de desarrollo y producción no tendrá la misma URL, es bastante doloroso administrarlo por su cuenta.
Mi solución para automatizar esto: usar la nueva función de interceptor HttpClient de Angular 4.3, combinada con el motor Express.
El interceptor detecta todas las solicitudes cuando está en el contexto del servidor para anteponer la URL completa.
import { Injectable, Inject, Optional } from '@angular/core'; import { HttpInterceptor, HttpHandler, HttpRequest } from'@angular/common/http'; @Injectable() export class UniversalInterceptor implements HttpInterceptor { constructor(@Optional() @Inject('serverUrl') protected serverUrl: string) {} intercept(req: HttpRequest<any>, next: HttpHandler) { const serverReq = !this.serverUrl ? req : req.clone({ url: ``${this.serverUrl}${req.url}`` }); return next.handle(serverReq); } }Luego proporciónelo en su AppServerModule:
import { NgModule } from '@angular/core'; import { ServerModule } from '@angular/platform-server'; import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { AppModule } from './app.module'; import { AppComponent } from './app.component'; import { UniversalInterceptor } from './universal.interceptor'; @NgModule({ imports: [ AppModule, ServerModule ], providers: [{ provide: HTTP_INTERCEPTORS, useClass: UniversalInterceptor, /* Multi is important or you will delete all the other interceptors */ multi: true }], bootstrap: [AppComponent] }) export class AppServerModule {}Ahora puede usar el motor Express para pasar la URL completa a Angular, simplemente actualice su server.js:
function angularRouter(req, res) { res.render('index', { req, res, providers: [{ provide: 'serverUrl', useValue: `${req.protocol}://${req.get('host')}` }] }); }