Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Angular Universal中获取完整的基本URL(包括服务器、端口和协议)?_Angular_Angular Universal - Fatal编程技术网

如何在Angular Universal中获取完整的基本URL(包括服务器、端口和协议)?

如何在Angular Universal中获取完整的基本URL(包括服务器、端口和协议)?,angular,angular-universal,Angular,Angular Universal,我需要获得Angular 2应用程序的完整基本URL(例如或),以便我可以将其传递给应用程序上下文中的第三方服务。应用程序的位置因其是开发环境、各种登台/测试环境还是生产环境而异,我希望动态检测它,因此不需要维护硬编码列表 A在过去已经提出过,但答案(即使用window.location.hostname或window.location.origin属性的某些版本)仅在浏览器呈现angular2应用程序时有效 我希望我的应用程序能够与Angular Universal配合使用,这意味着它需要在服

我需要获得Angular 2应用程序的完整基本URL(例如或),以便我可以将其传递给应用程序上下文中的第三方服务。应用程序的位置因其是开发环境、各种登台/测试环境还是生产环境而异,我希望动态检测它,因此不需要维护硬编码列表

A在过去已经提出过,但答案(即使用window.location.hostname或window.location.origin属性的某些版本)仅在浏览器呈现angular2应用程序时有效

我希望我的应用程序能够与Angular Universal配合使用,这意味着它需要在服务器端渲染,而服务器端无法访问诸如window.location之类的DOM对象


有没有办法做到这一点?作为参考,使用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')}`
    }]
  });
}