简体   繁体   中英

Angular's Service Worker prevents API to be called

I got an Angular app which uses API endpoints of a NestJS app.

In order to deploy the whole application to Heroku, I build Angular app and I put the content of /dist folder inside my NestJS app.

I use a Google authentication system. Basically, Angular calls an API endpoint which redirects user to Google's login screen and once done, it calls back my API which redirects back to a front URL like shown on this image: 身份验证过程

My issue with this is : when I have a service worker running in my Angular app, every time I click on the "Login with Google" link, I get the following error message:

ERROR Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'api/auth/google' Error: Cannot match any routes. URL Segment: 'api/auth/google'

After this, when I try to call an API endpoint directly through my browser, like https://myapp.herokuapp.com/api/albums , I get the same error message. But not with Postman for example.

So I decided to remove the service worker from the Angular part and everything works well now. So the service worker prevents me from calling API endpoints.

How to configure it correctly to avoid this kind of problem ?

In case you need some more information, see below:

Here is my main.ts :

async function bootstrap() {
  const configService = new ConfigService(CONFIG_SERVICE_PATH);
  const app = await NestFactory.create(AppModule);
  const httpRef = app.get(HTTP_SERVER_REF);

  app.enableCors();

  console.log('***** NODE ENV IS: ' + process.env.NODE_ENV); // <-- returns 'production' 
  console.log('***** IS PRODUCTION ? ' + configService.get('PRODUCTION')); // <-- returns 'true'

  if (configService.get('PRODUCTION') === 'true') {
    app.useStaticAssets(join(__dirname, '../front')); // <-- Angular folder
    app.useGlobalFilters(new AllExceptionsFilter(httpRef));
  } else {
    app.useStaticAssets(join(__dirname, '..', 'public'));
  }

  await app.listen(process.env.PORT || configService.get('PORT'));
}

My AllExceptionsFilter :

@Catch(NotFoundException)
export class AllExceptionsFilter extends BaseExceptionFilter {
  constructor(@Inject(HTTP_SERVER_REF) applicationRef: HttpServer) {
    super(applicationRef);
  }

  /**
   * This filter will serve the correct response for a request to the API or a request to the front part.
   */
  catch(exception: any, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const req = ctx.getRequest();

    if (req.path && req.path.startsWith('/api')) {
      super.catch(exception, host);
    } else {
      response.sendFile(resolve(__dirname, '../../front/index.html'));
    }
  }
}

My LoginComponent (Angular):

<a href="{{ loginUrl }}" class="google-button">
  <span class="google-button__text">Sign in with Google</span>

get loginUrl(): string {
  const url = environment.backendUrl + '/auth/google';
  console.log('Login url: ' + url); // <-- logs 'https://myapp.heroku.com/api/auth/google'
  return url;
}

@Flobesst, posted as an answer :)

Take a look at this post: Angular 5 and Service Worker: How to exclude a particular path from ngsw-config.json

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