Angular 5同构应用Express服务器运行问题求助
Hey David, let's break down solutions for both of your issues step by step:
1. Passing Query Params from server.ts to AppComponent.ts
In Angular Universal, you need to leverage the REQUEST token (provided by @angular/platform-server) to access server-side request details, then use TransferState to sync the params to the client (to avoid hydration mismatches). Here's how to implement this:
Step 1: Update AppComponent.ts
Add imports and inject the necessary dependencies to fetch and store the query param:
import { Component, Inject, PLATFORM_ID } from '@angular/core'; import { isPlatformServer } from '@angular/common'; import { REQUEST } from '@angular/platform-server'; import { TransferState, makeStateKey } from '@angular/platform-browser'; import { TranslateService } from '@ngx-translate/core'; // Define a unique key to store the lang param in TransferState const LANG_QUERY_KEY = makeStateKey<string>('langQuery'); @Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent { constructor( @Inject(PLATFORM_ID) private platformId: Object, @Inject(REQUEST) private request: any, private transferState: TransferState, private translateService: TranslateService ) { let activeLang: string; if (isPlatformServer(this.platformId)) { // Fetch the lang param from the server-side request activeLang = this.request.query.lang || 'en'; // Save the param to TransferState so the client can access it this.transferState.set(LANG_QUERY_KEY, activeLang); } else { // On the client, read from TransferState first, then fall back to URL activeLang = this.transferState.get(LANG_QUERY_KEY, 'en') || new URL(window.location.href).searchParams.get('lang') || 'en'; } // Now you can use activeLang in your component (e.g., set translation language) console.log('Active language:', activeLang); this.translateService.use(activeLang); } }
Step 2: Verify Module Imports
Ensure your AppServerModule has ServerTransferStateModule (which it does in your code) and AppModule has BrowserTransferStateModule:
// In AppModule.ts import { BrowserModule, BrowserTransferStateModule } from '@angular/platform-browser'; @NgModule({ imports: [ BrowserModule.withServerTransition({ appId: 'your-app-id' }), BrowserTransferStateModule, // ... other imports ] }) export class AppModule {}
Your existing server.ts code already passes req to res.render, which lets Angular inject the server request into your component—so no changes needed there.
2. Fixing translateService Error on Server-Side
The silent server-side error with translateService usually stems from missing language file loading or mismatched server/client state. Here are actionable fixes:
Option 1: Preload Translations on Server & Sync via TransferState
Preload language files on the server, save them to TransferState, and reuse them on the client to avoid duplicate HTTP requests and errors:
// In AppComponent.ts constructor (extend the earlier code) if (isPlatformServer(this.platformId)) { activeLang = this.request.query.lang || 'en'; this.transferState.set(LANG_QUERY_KEY, activeLang); // Preload translations on the server this.translateService.use(activeLang); this.translateService.getTranslation(activeLang).subscribe(translations => { const TRANSLATIONS_KEY = makeStateKey(`translations_${activeLang}`); this.transferState.set(TRANSLATIONS_KEY, translations); }); } else { activeLang = this.transferState.get(LANG_QUERY_KEY, 'en') || 'en'; const TRANSLATIONS_KEY = makeStateKey(`translations_${activeLang}`); const savedTranslations = this.transferState.get(TRANSLATIONS_KEY, null); if (savedTranslations) { // Use cached translations instead of making an HTTP call this.translateService.setTranslation(activeLang, savedTranslations); this.translateService.use(activeLang); } else { // Fallback to normal client-side loading this.translateService.use(activeLang); } }
Option 2: Ensure Server Can Access Language Files
Verify your server.ts serves static files correctly. Your current code has:
app.get('/web', express.static(join(DIST_FOLDER, 'browser'), { 'index': false })); app.get('/**', express.static(join(DIST_FOLDER, 'browser')));
This should serve files from dist/browser/assets/i18n/—double-check that your language JSON files exist in this directory after building.
Option 3: Capture Detailed Error Logs
Add error handling to server.ts to get more context about the silent error:
// Update your route handlers in server.ts routes.forEach(route => { app.get(`/${route}`, (req, res) => { console.log(req.query.lang); console.time(`GET: ${req.originalUrl}`); res.render(join(DIST_FOLDER, 'browser', 'index.html'), { req, res }, (err, html) => { if (err) { // Log the full error stack trace console.error('Server render error for route', route, err); res.status(500).send('Server error occurred'); } else { res.send(html); } }); console.timeEnd(`GET: ${req.originalUrl}`); }); // Repeat the error handling for the `/${route}/*` handler });
This will help you pinpoint exactly what's causing the ERROR [Error] on the server.
内容的提问来源于stack exchange,提问作者David Martinez Ros

