简体   繁体   中英

Angular universal share cookies between browser and server

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM