【问题标题】:Angular 2+ Universal is it possible to pass parameters from expressjs (without using url query string)?Angular 2+ Universal 是否可以从 expressjs 传递参数(不使用 url 查询字符串)?
【发布时间】:2017-11-02 20:48:45
【问题描述】:

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

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

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

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

ma​​in.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();
});

routes.ts

export const ROUTES: string[] = [
  '/error',
  '/:language',
  '/:language/download'
];

它可以工作,因为我能够配置 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 }
    ])

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

如何从 Angular Universal 的完整负载中传输更多数据(例如有关用户会话的信息)?

【问题讨论】:

  • 您找到解决方案了吗?我也遇到了同样的问题。

标签: express angular2-routing angular-universal


【解决方案1】:

我遇到了同样的问题,经过几个小时的搜索,我找到了一个适合我的解决方案here

在您的“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');
...

然后您可以访问您在 Angular4-component 或 -service 代码中的“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
    }
...

请注意,一旦您的页面在客户端浏览器中加载,“主机”提供程序将不再可用。相反,您必须从 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}!`);
});

【讨论】:

    猜你喜欢
    • 2017-08-13
    • 2016-11-02
    • 1970-01-01
    • 2012-02-07
    • 2014-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多