I used the following example to integrate cookies in browser and server: https://github.com/Angular-RU/universal-starter/blob/master/src/app/shared/storage/universal.storage.ts
Unfortunately the cookies don't seem to be shared between browser and server. I only see the cookie I set on browser side. So I expected the following code in my component to show the same cookies:
export class DashboardComponent {
constructor(@Inject(PLATFORM_ID) platformId: Object,
cookieService: CookieService) {
if (isPlatformServer(platformId)) {
console.log('get server');
console.log(cookieService.getAll());
}
else {
console.log('set browser');
cookieService.put('test', 'test1');
}
}
}
So when I load the page in the browser the cookie is set. When i refresh the page I expect that cookieService.getAll() is returning a value on the server side, but it's empty. Also when reloading the page I can see the cookies in the request header. Am I missing something or did I understand something wrong?
Here is the code that I have implemented:
app.module.ts
export function getRequest(): any {
return { headers: { cookie: document.cookie } };
}
@NgModule({
declarations: [
AppComponent,
LoaderComponent
],
imports: [
AppRoutingModule,
BrowserModule.withServerTransition({ appId: 'serverApp' }),
BrowserTransferStateModule,
BrowserAnimationsModule,
SharedModule,
HttpClientModule,
TransferHttpCacheModule,
CookieModule.forRoot(),
],
exports: [SharedModule],
providers: [
...
UniversalStorage,
{
// The server provides these in main.server
provide: REQUEST,
useFactory: getRequest,
},
],
bootstrap: [AppComponent]
})
export class AppModule { }
app.server.module.ts
@NgModule({
imports: [
AppModule,
ServerModule,
ServerTransferStateModule
],
bootstrap: [AppComponent],
providers: [
{
provide: AppConfigService,
useFactory: (transferState: TransferState) => new AppConfigService(new AssetServerLoader(transferState)),
deps: [TransferState]
},
// https://github.com/Angular-RU/universal-starter/blob/master/src/app/app.server.module.ts
// https://github.com/Gorniv/ngx-universal/blob/master/lib/src/cookie/README.md#installation
{
provide: REQUEST,
useValue: { cookie: '', headers: {} },
},
{
provide: RESPONSE,
useValue: {},
},
{
provide: CookieService,
useClass: CookieBackendService
},
{
provide: NgxRequest,
useValue: { cookie: '', headers: {} },
},
{
provide: NgxResponse,
useValue: {},
},
UniversalStorage
]
})
export class AppServerModule {}
server.ts
import 'zone.js/node';
import { APP_BASE_HREF } from '@angular/common';
import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { existsSync } from 'fs';
import { join } from 'path';
import * as https from 'https';
import * as fs from 'fs';
import { REQUEST, RESPONSE } from '@nguniversal/express-engine/tokens';
import { AppServerModule } from './src/main.server';
import * as cookieparser from 'cookie-parser';
// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
const server = express();
const distFolder = join(process.cwd(), 'dist/client-app/browser');
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';
// Our Universal express-engine (found @ https://github.com/angular/universal/tree/main/modules/express-engine)
server.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
}));
server.set('view engine', 'html');
server.set('views', distFolder);
// Example Express Rest API endpoints
// server.get('/api/**', (req, res) => { });
// Serve static files from /browser
server.get('*.*', express.static(distFolder, {
maxAge: '1y'
}));
// All regular routes use the Universal engine
server.get('*', (req, res) => {
res.render(indexHtml, {
req,
providers: [
{
provide: APP_BASE_HREF,
useValue: req.baseUrl
},
// Added for CookieService
// for http and cookies
{
provide: REQUEST,
useValue: req,
},
{
provide: RESPONSE,
useValue: res,
},
/// for cookie
{
provide: 'NgxRequest', useValue: (req)
},
{
provide: 'NgxResponse', useValue: (res)
}
]
});
});
return server;
}
function run(): void {
const port = process.env['PORT'] || 4200;
// https://medium.com/@dnlcyan/local-angular-ssr-with-https-b9d305dc620d
// Start up the Node server
let server;
if (process.argv && process.argv.includes('--ssl')) {
console.log('Using SSL');
// https certificates
const privateKey = fs.readFileSync('localhost.key');
const certificate = fs.readFileSync('localhost.crt');
server = https.createServer({ key: privateKey, cert: certificate }, app());
}
else {
server = app();
}
server.use(cookieparser());
server.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
run();
}
export * from './src/main.server';
I found an alternative library which seems to work: https://github.com/salemdar/ngx-cookie
Important is to also set the cookie in the request header in server.ts
server.get('*', (req, res) => {
req.cookies = req.headers.cookie;
I tried this for the library https://github.com/Gorniv/ngx-universal which I used first as well, but it didn't work.