Angular 2+ Universal是否可以从expressjs传递参数(不使用url查询字符串)?

Mic*_*lix 6 express angular2-routing angular-universal

我正在使用该示例使用nodejs和expressjs设置Angular 4 Universal:https: //github.com/FrozenPandaz/ng-universal-demo

我一直在尝试将数据从第一个完整页面加载传递到Angular 4 final应用程序.

用例是传输从标题中检测到的语言,以便从Angular 4服务器渲染器中吸收它,以便它可以使用正确的语言来翻译事物.

到目前为止,我发现的唯一方法是使用来自"/"路由的expressjs的HTTP头进行语言检测,并使用HTTP 302重定向到"/ fr",例如,如果用户语言是法语.

main.server.ts

app.param('language', function(req: any, res, next, language) {
  if(language.length == 2) 
  {
    req.language = language;
    next();
  } else {
    next(new Error('Invalid language found'));
  }
});

// Redirect incoming trafic without language in url (302 used so the browser do not seal that redirection if the user decides to change language and reload)
app.get('/', function(req, res) {   
  res.set('location', baseUrl + '/' + getLanguage(req);
  res.status(302).send();
});
Run Code Online (Sandbox Code Playgroud)

routes.ts

export const ROUTES: string[] = [
  '/error',
  '/:language',
  '/:language/download'
];
Run Code Online (Sandbox Code Playgroud)

它工作,因为我能够配置Angular 4路由器并检索当前路由,但它有点脏.

app.module.ts

RouterModule.forRoot([
      { path: '', component: HomeView, pathMatch: 'full'},
      { path: ':language/download', loadChildren: './+lazy/lazy.module#LazyModule'},
      { path: ':language/', redirectTo: ''},
      // Catch all if expressjs allowed this url
      { path: '**', component: HomeView }
    ])
Run Code Online (Sandbox Code Playgroud)

有没有比URL params更好的方法使用Angular Universal将数据从ExpressJS传递到Angular 4应用程序?

如何从满负荷的Angular Universal传输更多数据(例如关于用户会话的信息)?

Hum*_*jät 6

我有同样的问题,几个小时的搜索后,我发现,是为我工作的解决方案在这里.

在'main.server.ts'文件中,你必须将'extraProviders'添加到app.engine()看起来像这样的函数中:

...
let template = readFileSync(join(__dirname, '..', 'dist', 'index.html')).toString();

app.engine('html', (_, options, callback) => {
  const opts = { 
     document: template
    ,url: options.req.url
    ,extraProviders: [
                         { provide: 'host',  useFactory: () => options.req.get('host') }
                        ,{ provide: 'PLACEHOLDER',  useFactory: () => 'SOME PLACEHOLDER TEXT' }
                     ]
  };

  renderModuleFactory(AppServerModuleNgFactory, opts)
    .then(html => callback(null, html));
});

app.set('view engine', 'html');
...
Run Code Online (Sandbox Code Playgroud)

然后,您可以访问Angular4组件或服务代码中'main.server.ts'文件中定义的提供程序,如下所示:

import { Injectable, Injector, PLATFORM_ID }  from '@angular/core';
import { isPlatformServer } from '@angular/common';


@Injectable()
export class I18nService {

    constructor(
          private injector: Injector
         ,@Inject(PLATFORM_ID) private platformId: Object
        ){
        let host = null;
        if (isPlatformServer(this.platformId)) {
            // -> server rendered
            host = this.injector.get('host');
            //do something with host here
        } else {
            // -> browser rendered
            host = document.location...
        }
        console.log(host);
        //do something clever with 'host' here
    }
...
Run Code Online (Sandbox Code Playgroud)

请注意,一旦您的页面加载到客户端浏览器中,"主机"提供商将不再可用.相反,你必须从JS api获得主机.

这是我完整的'main.server.ts'文件:

import 'reflect-metadata';
import 'zone.js/dist/zone-node';
import { platformServer, renderModuleFactory } from '@angular/platform-server'
import { enableProdMode } from '@angular/core'
import { AppServerModuleNgFactory } from '../dist/ngfactory/src/app/app.server.module.ngfactory'
import * as express from 'express';
import { readFileSync } from 'fs';
import { join } from 'path';
import * as compression from 'compression';

const PORT = 4200;

enableProdMode();

const app = express();

let template = readFileSync(join(__dirname, '..', 'dist', 'index.html')).toString();

app.engine('html', (_, options, callback) => {
  const opts = { 
     document: template
    ,url: options.req.url
    ,extraProviders: [
                         { provide: 'request', useFactory: () => options.req }
                        ,{ provide: 'host',  useFactory: () => options.req.get('host') }
                     ]
  };

  renderModuleFactory(AppServerModuleNgFactory, opts)
    .then(html => callback(null, html));
});

app.set('view engine', 'html');
app.set('views', 'src');
app.use(compression());

app.get('*.*', express.static(join(__dirname, '..', 'dist')));

app.get('*', (req, res) => {
  res.render('index', { req });
});

app.listen(PORT, () => {
  console.log(`listening on http://localhost:${PORT}!`);
});
Run Code Online (Sandbox Code Playgroud)