如何将所有路由重定向到nest.js中的index.html(Angular)?
Posted
技术标签:
【中文标题】如何将所有路由重定向到nest.js中的index.html(Angular)?【英文标题】:How to redirect all routes to index.html (Angular) in nest.js? 【发布时间】:2019-07-17 04:58:54 【问题描述】:我正在制作 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
@Controller('*')
export class AppController
@Get()
@Render('index.html')
root()
return ;
当我打开 localhost:3000/
时,它运行良好,但如果我打开 localhost:3000/some_route
,服务器会显示 500 internal error
并显示 Can not find html module
。
我正在寻找为什么我会收到这个错误,每个人都说set default view engine like ejs or pug
,但我不想使用一些引擎,我只想发送由 angular 构建的普通 html,而不像res.sendFile('path_to_file')
那样进行黑客攻击。请帮忙
【问题讨论】:
【参考方案1】:您只能将setBaseViewsDir
和@Render()
与车把(hbs)等视图引擎一起使用;但是,对于提供静态文件 (Angular),您只能使用 useStaticAssets
和 response.sendFile
。
要从所有其他路线为index.html
提供服务,您有两种可能性:
A) 中间件
您可以创建一个执行重定向的中间件,请参阅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')));
;
然后为所有路由注册中间件:
export class ApplicationModule implements NestModule
configure(consumer: MiddlewaresConsumer): void
consumer.apply(FrontendMiddleware).forRoutes(
path: '/**', // For all routes
method: RequestMethod.ALL, // For all methods
,
);
B) 全局错误过滤器
您可以将所有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')));
然后将其注册为您的main.ts
中的全局过滤器:
app.useGlobalFilters(new NotFoundExceptionFilter());
【讨论】:
非常感谢!我认为如果我可以设置useStaticAssets
并从@Render()
返回文件会很容易。但它似乎比我想象的要复杂。【参考方案2】:
2019 年 12 月 10 日的更新答案
你需要创建中间件来发送react index.html
创建中间件文件
frontend.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'));
在
中包含中间件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
);
参考应用结构:
enter image description here
【讨论】:
好的艾伦,但 OP 要求 Angular。我同意它是一样的。【参考方案3】:您还可以将 Cloud Functions for Firebase 与 Firebase 托管结合使用。 main.ts 中的内容非常好,使用这种方法,您甚至不需要控制器。你应该如下:
-
将
index.html
重命名为index2.html
。这对于渲染您的路由路径很重要,否则您将在所有路由上正常渲染,不包括根 /
。
更新angular.json
以获得以下"index": "apps/myapp/src/index2.html",
(只需将index.html
更改为index2.html
)。 注意:index.html 的路径对您来说可能不同,我使用的是Nx 工作区。
将templatePath: join(BROWSER_DIR, 'index2.html'),
添加到NestJS 的ApplicationModule
,很可能你在server 目录中将文件命名为app.module.ts。
像这样:
@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
)
]
)
初始化 Firebase Cloud Functions 和 Firebase Hosting,如何设置可以查看https://hackernoon.com/deploying-angular-universal-v6-with-firebase-c86381ddd445 或https://blog.angularindepth.com/angular-5-universal-firebase-4c85a7d00862
编辑您的 firebase.json。
它应该看起来像这样,或者至少是 hosting
部分。
"hosting":
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"public": "functions/dist/apps/path/to/browser",
"rewrites": [
"function": "angularUniversalFunction",
"source": "**"
]
-
在您的 main.ts 中,您需要在您的服务器上设置 Cloud Functions。
在极简主义的情况下,它会喜欢这样的东西:
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 (s-s-r).
exports.angularUniversalFunction = functions.https.onRequest(expressApp);
使用这种方法,您不必关心 NestJS 端的路由。您可以在 Angular 端设置所有内容,仅此而已。 Angular 负责路由。您可能注意到这是服务器端渲染 (s-s-r),但是可以结合使用 NestJS + Cloud Functions for Firebase 将所有路由重定向到 index.html
(或更准确地说是 index2.html
)。另外,您还有“免费”的 s-s-r :)
要展示的项目:
1) Angular + Angular Universal (s-s-r) + Cloud Functions for Firebase:https://github.com/Ismaestro/angular8-example-app(缺少 NestJS)。
2) Angular + NestJS:https://github.com/kamilmysliwiec/universal-nest(缺少 Firebase 的云函数)。
【讨论】:
以上是关于如何将所有路由重定向到nest.js中的index.html(Angular)?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Laravel 4 中将一个路由重定向到 HTTPS,将所有其他路由重定向到 HTTP?
.htaccess - 将所有 URL + 现有目录重定向到 index.php