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

标签 express angular2-routing angular-universal

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

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

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

到目前为止,我发现的唯一方法是使用来自expressjs的“/”路由中的HTTP header 进行语言检测,并使用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 的完整负载中传输更多数据(例如有关用户 session 的信息)?

最佳答案

我遇到了同样的问题,经过几个小时的搜索,我找到了一个适合我的解决方案 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 组件或服务代码的“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}!`);
});

关于express - Angular 2+ Universal是否可以从expressjs传递参数(不使用url查询字符串)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44312023/

相关文章:

node.js - 从 Golang 后端流式传输文件到 Node 前端

javascript - 在 Express 中的 app.listen 之前等待异步函数完成

node.js - 在nodeJS中处理长时间运行的进程的可能方法

Angular 2路由,如何访问url中的语言参数

angular - 服务器端不呈现 http 请求 [Angular Universal]

javascript - 如何使用 JavaScript 显示带有数据库元素的选项 (HTML)

Angular 2 - 成功登录后重定向不起作用

Angular2 - 将 routerLink 参数添加到所选表值

angular - HttpHeaders.applyUpdate 'Cannot read property ' 长度'未定义' Angular 通用服务器

angular - SSR with (RE)Hydration in Angular