Search code examples
angularangular-universal

Angular Universal keeps loading forever if an error occurs


I have an Angular Universal application running, which works fine, except for the fact that if an error occurs in the Angular code while rendering, instead of just spitting out a 500 response, it'll keep loading forever, until the server decides it's enough and spits out a 503.

An example of a failing page is https://msp-navigator.com/company/BpQzpAHaSFWbXvsgt3gc/saaslio. This one fails because it's only accessible to Admins, but in the resolve, due to a mistake, if you're not logged in, the user is undefined and the check fails. (user.roles?.includes('Admin') => user?.roles?.includes('Admin'). An example of a page that doesn't fail is https://msp-navigator.com/company/FsAqspiNe7jPCyOsIhT7/saaslio

The route in server.ts is defined like this:

  server.get('*', async (req, res, next) => {
    const origin = 'https://' + req.header('host');

    let settings: any;
    try {
      settings = await axios.get(environment.config.apiUrl + '/settings', {headers: {origin}});
    } catch (e) {
      res.sendStatus(404);

      return;
    }

    const transaction = Sentry.startTransaction({ op: 'main', name: 'Main' });
    Sentry.configureScope(scope => scope.setSpan(transaction));

    try {
      console.log('test 1');
      res.render(indexHtml, {
          req,
          providers: [
            { provide: APP_BASE_HREF, useValue: req.baseUrl },
            { provide: SETTINGS, useValue: settings.data }
          ],
        });
    } catch (e) {
      console.log('test 2');
      res.send(500);
    }

    transaction.finish();
  });

In case of an error "test 1" is logged, then the error, but "test 2" is never logged.

I'm not sure what other code I can share, but please ask.

Any ideas on how I can resolve this?


Solution

  • This is because render is asynchronous, which means that errors will not be handled by your try/catch. But you can provide a callback to render

    res.render(indexHtml, {
          req,
          providers: [
            { provide: APP_BASE_HREF, useValue: req.baseUrl },
            { provide: SETTINGS, useValue: settings.data }
          ],
        }, (err: Error, html: string) =>
    {
    
      if(!html)
      {
          res.status(500);
      }
      res.send(html || err.message);
    });