简体   繁体   English

如何将所有路由重定向到 nest.js 中的 index.html (Angular)?

[英]How to redirect all routes to index.html (Angular) in nest.js?

I am making Angular + NestJS app, and I want to send index.html file for all routes.我正在制作 Angular + NestJS 应用程序,我想为所有路由发送index.html文件。

main.ts主文件

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useStaticAssets(join(__dirname, '..', 'frontend', 'dist', 'my-app'));
  app.setBaseViewsDir(join(__dirname, '..', 'frontend', 'dist', 'my-app'));
  await app.listen(port);
}

app.controller.ts app.controller.ts

@Controller('*')
export class AppController {

  @Get()
  @Render('index.html')
  root() {
    return {};
  }
}

It works fine while I open localhost:3000/ , but if I open localhost:3000/some_route the server falls with 500 internal error and says Can not find html module .当我打开localhost:3000/时它工作正常,但是如果我打开localhost:3000/some_route服务器会出现500 internal error并说Can not find html module I was searching why I am getting this error and everyone says set default view engine like ejs or pug , but I don't want to use some engines, I just want to send plain html built by angular without hacking like res.sendFile('path_to_file') .我在搜索为什么我会收到这个错误,每个人都说set default view engine like ejs or pug ,但我不想使用某些引擎,我只想发送由 angular 构建的纯 html,而不像res.sendFile('path_to_file') Please help请帮忙

You can only use setBaseViewsDir and @Render() with a view engine like handlebars (hbs);您只能将setBaseViewsDir@Render()与像把手 (hbs) 这样的视图引擎一起使用; for serving static files (Angular), however, you can only use useStaticAssets and response.sendFile .但是,对于提供静态文件(Angular),您只能使用useStaticAssetsresponse.sendFile

To serve index.html from all other routes you have a couple of possibilities:要从所有其他路由提供index.html ,您有几种可能性:

A) Middleware A) 中间件

You can create a middleware that does the redirect, see this article :您可以创建一个执行重定向的中间件,请参阅这篇文章

@Middleware()
export class FrontendMiddleware implements NestMiddleware {
  resolve(...args: any[]): ExpressMiddleware {
    return (req, res, next) => {
      res.sendFile(path.resolve('../frontend/dist/my-app/index.html')));
    };
  }
}

and then register the middleware for all routes:然后为所有路由注册中间件:

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

B) Global Error Filter B) 全局错误过滤器

You can redirect all NotFoundExceptions to your index.html :您可以将所有NotFoundExceptions重定向到您的index.html

@Catch(NotFoundException)
export class NotFoundExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    response.sendFile(path.resolve('../frontend/dist/my-app/index.html')));
  }
}

and then register it as a global filter in your main.ts :然后将其注册为main.ts的全局过滤器:

app.useGlobalFilters(new NotFoundExceptionFilter());

Updated Answer for December 10, 2019 2019 年 12 月 10 日的更新答案

You need to create middleware for sending the react index.html您需要创建中间件来发送 react index.html

Create middleware file创建中间件文件

frontend.middleware.ts前端.middleware.ts

import { NestMiddleware, Injectable } from '@nestjs/common';
import {Request, Response} from "express"
import { resolve } from 'path';

@Injectable()
export class FrontendMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: Function) {
    res.sendFile(resolve('../../react/build/index.html'));
  }
}

Include middleware in包括中间件

app.module.ts app.module.ts

import { FrontendMiddleware } from './frontend.middleware';
import {
  Module,
  MiddlewareConsumer,
  RequestMethod,
} from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {
  configure(frontEnd: MiddlewareConsumer) {
    frontEnd.apply(FrontendMiddleware).forRoutes({
      path: '/**', // For all routes
      method: RequestMethod.ALL, // For all methods
    });
  }
}

App Structure for Reference:供参考的应用程序结构:

enter image description here在此处输入图片说明

You can also use Cloud Functions for Firebase together with Firebase Hosting.您还可以将 Cloud Functions for Firebase 与 Firebase 托管一起使用。 What you have in main.ts is perfectly fine, with this approach you even don't need a controller.您在main.ts拥有的内容非常好,使用这种方法您甚至不需要控制器。 You should go as follows:你应该按照以下步骤进行:

  1. Rename index.html to index2.html .index.html重命名为index2.html This is important to render your route path, otherwise you will have rendering working fine on all routes, excluding the root / .这对于渲染您的路线路径很重要,否则您将在所有路线上都能正常渲染,不包括根/
  2. Update angular.json to have the following "index": "apps/myapp/src/index2.html", (Simply change index.html to index2.html ).更新angular.json以具有以下"index": "apps/myapp/src/index2.html", (只需将index.html更改为index2.html )。 Note: path to the index.html might be different for you, I'm using Nx workspace .注意:你的 index.html 路径可能不同,我使用的是Nx workspace
  3. Add templatePath: join(BROWSER_DIR, 'index2.html'), to NestJS's ApplicationModule , most probably you name the file as app.module.ts in a server directory.添加templatePath: join(BROWSER_DIR, 'index2.html'),到 NestJS 的ApplicationModule ,很可能你在服务器目录中将该文件命名为app.module.ts

Like so:像这样:

@Module({
  imports: [
    AngularUniversalModule.forRoot({
      bundle: require('./path/to/server/main'), // Bundle is created dynamically during build process.
      liveReload: true,
      templatePath: join(BROWSER_DIR, 'index2.html'),
      viewsPath: BROWSER_DIR
    })
  ]
})
  1. Initialize Firebase Cloud Functions and Firebase Hosting, for how to set up this you can check https://hackernoon.com/deploying-angular-universal-v6-with-firebase-c86381ddd445 or https://blog.angularindepth.com/angular-5-universal-firebase-4c85a7d00862初始化 Firebase Cloud Functions 和 Firebase Hosting,有关如何设置,您可以查看https://hackernoon.com/deploying-angular-universal-v6-with-firebase-c86381ddd445https://blog.angularindepth.com/angular -5-universal-firebase-4c85a7d00862

  2. Edit your firebase.json .编辑您的firebase.json

It should look like that, or at least the hosting part.它应该看起来像那样,或者至少是hosting部分。

{
  "hosting": {
    "ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
    "public": "functions/dist/apps/path/to/browser",
    "rewrites": [
      {
        "function": "angularUniversalFunction",
        "source": "**"
      }
    ]
  }
} 
  1. In your main.ts you need to set up Cloud Functions on your server.main.ts 中,您需要在服务器上设置 Cloud Functions。

In a minimialistic case it would like something like that:在简约的情况下,它会像这样:

import * as admin from 'firebase-admin';
import * as functions from 'firebase-functions';

admin.initializeApp(); // Initialize Firebase SDK.
const expressApp: Express = express(); // Create Express instance.

// Create and init NestJS application based on Express instance.
(async () => {
  const nestApp = await NestFactory.create<NestExpressApplication>(
    ApplicationModule,
    new ExpressAdapter(expressApp)
  );
  nestApp.init();
})().catch(err => console.error(err));

// Firebase Cloud Function for Server Side Rendering (SSR).
exports.angularUniversalFunction = functions.https.onRequest(expressApp);

With this approach you don't have to care about routes on the NestJS side.使用这种方法,您不必关心 NestJS 端的路由。 You can set up everything on the Angular side, and that's all.您可以在 Angular 端设置所有内容,仅此而已。 Angular takes care for routing. Angular 负责路由。 As you probably noticed this is Server-Side Rendering (SSR), but redirection of all routes to index.html (or more precisely index2.html ) can be done using NestJS + Cloud Functions for Firebase in conjuction.您可能已经注意到这是服务器端渲染 (SSR),但是可以结合使用 NestJS + Cloud Functions for Firebase 将所有路由重定向到index.html (或更准确地说index2.html )。 Plus you have a SSR "for free" :)另外你有一个“免费”的 SSR :)

Projects to showcase:展示项目:

1) Angular + Angular Universal (SSR) + Cloud Functions for Firebase: https://github.com/Ismaestro/angular8-example-app (missing NestJS). 1) Angular + Angular Universal (SSR) + Cloud Functions for Firebase: https : //github.com/Ismaestro/angular8-example-app (缺少 NestJS)。

2) Angular + NestJS: https://github.com/kamilmysliwiec/universal-nest (missing Cloud Functions for Firebase). 2) Angular + NestJS: https : //github.com/kamilmysliwiec/universal-nest (缺少 Firebase 的云函数)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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