如何在Angular Universal中获取完整的基本URL(包括服务器、端口和协议)?
我需要获得Angular 2应用程序的完整基本URL(例如或),以便我可以将其传递给应用程序上下文中的第三方服务。应用程序的位置因其是开发环境、各种登台/测试环境还是生产环境而异,我希望动态检测它,因此不需要维护硬编码列表 A在过去已经提出过,但答案(即使用window.location.hostname或window.location.origin属性的某些版本)仅在浏览器呈现angular2应用程序时有效 我希望我的应用程序能够与Angular Universal配合使用,这意味着它需要在服务器端渲染,而服务器端无法访问诸如window.location之类的DOM对象如何在Angular Universal中获取完整的基本URL(包括服务器、端口和协议)?,angular,angular-universal,Angular,Angular Universal,我需要获得Angular 2应用程序的完整基本URL(例如或),以便我可以将其传递给应用程序上下文中的第三方服务。应用程序的位置因其是开发环境、各种登台/测试环境还是生产环境而异,我希望动态检测它,因此不需要维护硬编码列表 A在过去已经提出过,但答案(即使用window.location.hostname或window.location.origin属性的某些版本)仅在浏览器呈现angular2应用程序时有效 我希望我的应用程序能够与Angular Universal配合使用,这意味着它需要在服
有没有办法做到这一点?作为参考,使用asp.net core作为后端(使用默认的dotnet新角度模板)。多亏了estus的帮助,我成功地拼凑出了一些有用的东西 看起来大多数Angular Universal模板实际上让服务器传递一个名为“originUrl”的区域参数,服务器呈现方法使用该参数来提供一个可以在其他方法中注入的ORIGIN_URL标记。我找不到任何关于这个的文档,但是你可以看到 所以如果你写这样的东西
export function getBaseUrl() {
if (Zone.current.get("originUrl")) {
return Zone.current.get('originUrl');
} else if (location) {
return location.origin;
} else {
return 'something went wrong!';
}
}
您应该能够在服务器和客户端上获得完整的源URL。现在我正在使用服务器。ts:
之后,我可以在location.service.ts中使用:
我有一些angular 5和angular universal的工作代码 在server.ts中,替换此
app.engine('html', (_, options, callback) => {
let engine = ngExpressEngine({
bootstrap: AppServerModuleNgFactory,
providers: [
{ provide: 'request', useFactory: () => options.req, deps: [] },
provideModuleMap(LAZY_MODULE_MAP)
]
});
engine(_, options, callback);
});
在角度方面,你们可以用下面的代码得到主机
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.');
}
}
}
您会发现所有来自Http请求的内容都不会预先呈现:这是因为Universal需要绝对URL 由于您的开发和生产服务器不会有相同的URL,因此单独管理它是非常痛苦的 我的自动化解决方案是:使用Angular 4.3的新HttpClient拦截器功能,并结合Express引擎 拦截器在服务器上下文中捕获所有请求,以预先发送完整URL
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);
}
}
现在,您可以使用Express engine将完整URL传递给Angular,只需更新您的server.js:
function angularRouter(req, res) {
res.render('index', {
req,
res,
providers: [{
provide: 'serverUrl',
useValue: `${req.protocol}://${req.get('host')}`
}]
});
}
Universal中存在源URL提供程序。我建议检查一下它是否有效。无论如何,一个好习惯是提供包含主机名的环境变量/提供程序。API调用的主机可能不同,您可能迟早会做相同的事情。请尝试像
@inject(ORIGIN\u URL)@Optional()ORIGIN
那样插入它,并在服务器端调试它所等同的内容。谢谢您的提示!我对Angular有点陌生,所以请原谅我,如果这是显而易见的,但是你知道我如何检查ORIGIN\u URL是否能提供我所需要的吗?我试着像这样要求我的组件的构造函数:构造函数(@Inject(ORIGIN\u URL)private\u ORIGIN),但我得到了错误“无法解析HomeComponent的所有参数”。我尝试将它添加到我的ngModule decorator的Providers数组中,但这似乎也没有改变错误。也许有一些语法细节我不知道?它应该被标记为可选的,因为它在客户端不存在。谢谢!看起来它在服务器端具有该值。我通过将其呈现到{{}中包装的模板(客户端不触及该模板)来解决这个问题。奇怪的是,尽管我的构造函数看起来像构造函数(@Optional()@Inject(ORIGIN_URL)ORIGIN),但客户端仍不断抱怨相同的错误(“无法解析所有参数”)。您能详细说明一下如何使用它吗?我想在我的代码中使用子域访问主机。在我的情况下,这不起作用this.request.get('host')
return always 127.0.0.1:4000此处示例:Zone.current.get(“originUrl”)
在Angular 5中对我不起作用。@xuhcc-找到解决方案了吗?@kris_IV-是,我按照@chintan adatiya的建议添加了请求
提供程序。@XUCC解决方案不适合我-我在第一次请求时获得主机:127.0.0.1:4000,但我需要域/@kris_IV当您的angular universal应用程序在反向代理后运行时,可能会发生这种情况。尝试检查X-Forwarded-For
和X-Real-IP
头。当我在本地运行它时,它工作正常,但在服务器上它会给出一个错误,即没有提供程序请求。有解决办法吗?我正在处理您的服务器可能有问题。t非常好。对我有效。看起来这可能有效:
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);
}
}
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 {}
function angularRouter(req, res) {
res.render('index', {
req,
res,
providers: [{
provide: 'serverUrl',
useValue: `${req.protocol}://${req.get('host')}`
}]
});
}