我需要获取Angular 2应用的完整基本网址(例如http://localhost:5000或https://productionserver.com),以便我可以将其传递给应用环境中的第三方服务。应用程序的位置取决于它是开发,各种登台/测试环境还是生产,我想动态检测它,因此我不需要维护硬编码列表
过去曾提出similar question,但答案(即使用某些版本的window.location.hostname或window.location.origin属性)仅在angular2应用程序呈现时才有效。浏览器。
我希望我的应用程序能够与Angular Universal一起使用,这意味着它需要在服务器端呈现,而不能访问像window.location这样的DOM对象。
任何想法如何实现这一目标?供参考,使用asp.net核心作为后端(使用默认的dotnet新角度模板)。
答案 0 :(得分:17)
我有点角度5和角度通用的工作代码
在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);
});
并且在Angular方面,您可以使用以下代码获取主机
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.');
}
}
}
答案 1 :(得分:4)
现在我正在使用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)
]
}));
之后我可以在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
}
}
答案 2 :(得分:1)
您会发现来自Http请求的所有内容都不会被预渲染:这是因为Universal需要绝对URL。
由于您的开发和生产服务器将没有相同的URL,因此独自管理它非常痛苦。
我的自动化解决方案:结合Angular 4.3的新HttpClient拦截器功能和Express引擎。
在服务器上下文中,拦截器会捕获所有请求,以在整个URL之前添加前缀。
expose: <port>
然后在您的AppServerModule中提供它:
EXPOSE <port>
现在,您可以使用Express引擎将完整的URL传递给Angular,只需更新server.js即可:
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);
}
}
答案 3 :(得分:0)
感谢来自estus的帮助,我设法将一些有效的东西混在一起。
看起来大多数Angular Universal模板实际上都让服务器传递一个名为“originUrl”的zone参数,服务器呈现方法使用该参数来提供可以在其他方法中注入的ORIGIN_URL标记。我找不到任何关于此的文档,但您可以看到an example here。
所以,如果你写这样的东西......
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。