web-dev-qa-db-ja.com

Angular Universal?)で完全なベースURL(サーバー、ポート、プロトコルを含む)を取得する方法

完全なベースURLを取得する必要があります(例: http:// localhost:5000 または https:// productionserver Angular 2アプリの.com )。これにより、アプリのコンテキストでサードパーティのサービスに渡すことができます。アプリの場所は、開発、さまざまなステージング/テスト環境、本番のいずれであるかによって異なります。動的に検出したいので、ハードコードされたリストを維持する必要はありません。

同様の質問 が過去に提起されましたが、回答(つまり、window.location.hostnameまたはwindow.location.Originプロパティのバージョンを使用します) )angular2アプリがブラウザによってレンダリングされている場合にのみ機能します。

アプリをAngular Universalで動作させたいのですが、これは、window.locationなどのDOMオブジェクトにアクセスできないサーバー側でアプリをレンダリングする必要があることを意味します。

これを達成する方法はありますか?参考までに、バックエンドとしてasp.netコアを使用(デフォルトのdotnet new angularテンプレートを使用)。

9

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);
});

そして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.');
        }
    }
}
9
chintan adatiya

今私は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
  }
}
1
Ivan Kalashnik

Estusの助けを借りて、うまくいくものを一緒にハックすることができました。

ほとんどのAngularのように見えます。ユニバーサルテンプレートは、実際にはサーバーが "originUrl"と呼ばれるゾーンパラメータを渡します。これに関するドキュメントは見つかりませんでしたが、 ここの例 を見ることができます。

したがって、次のようなものを書くと...

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を取得できるはずです。

1

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);
  }
}

次に、それを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 {}

これで、Expressエンジンを使用して完全なURLをAngularに渡すことができます。server.jsを更新するだけです。

 function angularRouter(req, res) { 
  res.render('index', {
    req,
    res,
    providers: [{
      provide: 'serverUrl',
      useValue: `${req.protocol}://${req.get('Host')}`
    }]
  });
}
0
Kooldandy