admin管理员组

文章数量:1323335

I'm developing a back-end in Nest.js which should serve React generated index.html on all root-level routes (/about, /contact-us and so on) but not on the ones starting with /api. This is what I currently do in the AppController:

@Get('/')
@Get('/contact')
@Get('/about-us')
fileServingRoutes(@Res() res: Response) {
  return res.sendFile('index.html', { root: AppModule.getStaticAssetsRootPath() });
}

Is there any way to do this without manually defining all routes which have to send file back?

I'm developing a back-end in Nest.js which should serve React generated index.html on all root-level routes (/about, /contact-us and so on) but not on the ones starting with /api. This is what I currently do in the AppController:

@Get('/')
@Get('/contact')
@Get('/about-us')
fileServingRoutes(@Res() res: Response) {
  return res.sendFile('index.html', { root: AppModule.getStaticAssetsRootPath() });
}

Is there any way to do this without manually defining all routes which have to send file back?

Share edited Mar 25, 2019 at 13:24 Kim Kern 60.6k20 gold badges217 silver badges214 bronze badges asked Mar 25, 2019 at 9:51 Nikola StojakovićNikola Stojaković 2,3056 gold badges29 silver badges54 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 4

I'd remend following Bo's great article on serving SPAs. The setup has Angular in mind but is the same for a React app.

Gist

Define a middleware function that redirects all routes except /api to your index.html.

@Middleware()
export class FrontendMiddleware implements NestMiddleware {
  use(req, res, next) {
    const { url } = req;
    if (url.indexOf('/api') === 1) {
      next();
    } else {
      res.sendFile(resolvePath('index.html'));
    }
  }
}

Register it for all routes in your AppModule:

export class ApplicationModule implements NestModule {
  configure(consumer: MiddlewareConsumer): void {
    consumer.apply(FrontendMiddleware).forRoutes(
      {
        path: '/**',
        method: RequestMethod.ALL,
      },
    );
  }
}

I slightly modified Kim's solution for my needs (I'm using version 5.8.0) so in case you get the error that your middleware doesn't implement NestMiddleware interface properly (because of the resolve method), you can use functional middleware;

export function FrontendMiddleware(req, res, next) {
  const { baseUrl } = req;
  if (baseUrl.indexOf('/api') === 0) {
    next();
  } else {
    res.sendFile(<path to your index.html file>);
  }
}

I also used baseUrl instead of url property which returned / when I tried to access /api route.

You may also consider using @nestjs/serve-static package. It helps you serve static content such as React and other SPAs.

The configuration has an option to exclude the routes you want to exclude.

For example, you may use prefix your API routes with "api":

app.setGlobalPrefix('api')

and use ServeStaticModule from @nestjs/serve-static to serve your React.

A basic configuration in AppModule:

...
@Module({
  imports: [
    ServeStaticModule.forRoot({
      rootPath: join(__dirname, '..', 'client'),
      exclude: ['api/*'],
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

本文标签: javascriptExcluding all api routes in Nestjs to serve React appStack Overflow