我正在使用该示例通过 nodejs 和expressjs 设置 Angular 4 Universal : https://github.com/FrozenPandaz/ng-universal-demo
我一直在尝试将数据从第一个整页加载传递到 Angular 4 最终应用程序。
用例是传输从 header 中检测到的语言,以从 Angular 4 服务器渲染器吸收它,以便它可以使用正确的语言来翻译内容。
到目前为止,我发现的唯一方法是使用来自expressjs的“/”路由中的HTTP header 进行语言检测,并使用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();
});
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/