Angular SSR项目中添加Express API路由无法正常工作
Angular SSR中Express API路由不生效的问题解决
问题场景
在Angular SSR项目的Express服务器中新增了/api/test接口路由,但通过Postman请求http://localhost:4200/api/test时,触发了Angular路由的NG04002错误,接口逻辑并未执行。
现有server.ts代码
import { APP_BASE_HREF } from '@angular/common'; import { CommonEngine } from '@angular/ssr'; import express from 'express'; import { fileURLToPath } from 'node:url'; import { dirname, join, resolve } from 'node:path'; import bootstrap from './src/main.server'; export function app(): express.Express { const server = express(); const serverDistFolder = dirname(fileURLToPath(import.meta.url)); const browserDistFolder = resolve(serverDistFolder, '../browser'); const indexHtml = join(serverDistFolder, 'index.server.html'); const commonEngine = new CommonEngine(); server.set('view engine', 'html'); server.set('views', browserDistFolder); // 静态文件服务 server.get('**', express.static(browserDistFolder, { maxAge: '1y', index: 'index.html', })); // 新增的API路由 server.get('/api/test', function(req, res){ console.log("test first") res.json({test:"test"}) }) // Angular SSR渲染路由 server.get('**', (req, res, next) => { const { protocol, originalUrl, baseUrl, headers } = req; commonEngine .render({ bootstrap, documentFilePath: indexHtml, url: `${protocol}://${headers.host}${originalUrl}`, publicPath: browserDistFolder, providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }], }) .then((html) => res.send(html)) .catch((err) => next(err)); }); return server; } function run(): void { const port = process.env['PORT'] || 4000; const server = app(); server.listen(port, () => { console.log(`Node Express server listening on http://localhost:${port}`); }); } run();
触发的错误信息
ERROR RuntimeError: NG04002: Cannot match any routes. URL Segment: 'api/test' at Recognizer.noMatchError (angular-client/.angular/cache/18.2.10/angular-client/vite/deps_ssr/@angular_router.js:2732:12) at eval (angular-client/.angular/cache/18.2.10/angular-client/vite/deps_ssr/@angular_router.js:2764:20) at eval (angular-client/.angular/cache/18.2.10/angular-client/vite/deps_ssr/chunk-77RZBIYQ.js:5844:49) at OperatorSubscriber2.OperatorSubscriber2._this._error (angular-client/.angular/cache/18.2.10/angular-client/vite/deps_ssr/chunk-77RZBIYQ.js:909:13) at OperatorSubscriber2.Subscriber2.error (angular-client/.angular/cache/18.2.10/angular-client/vite/deps_ssr/chunk-77RZBIYQ.js:520:16) at OperatorSubscriber2.Subscriber2._error (angular-client/.angular/cache/18.2.10/angular-client/vite/deps_ssr/chunk-77RZBIYQ.js:543:28) at OperatorSubscriber2.Subscriber2.error (angular-client/.angular/cache/18.2.10/angular-client/vite/deps_ssr/chunk-77RZBIYQ.js:520:16) at OperatorSubscriber2.Subscriber2._error (angular-client/.angular/cache/18.2.10/angular-client/vite/deps_ssr/chunk-77RZBIYQ.js:543:28) at OperatorSubscriber2.Subscriber2.error (angular-client/.angular/cache/18.2.10/angular-client/vite/deps_ssr/chunk-77RZBIYQ.js:520:16) at OperatorSubscriber2.Subscriber2._error (angular-client/.angular/cache/18.2.10/angular-client/vite/deps_ssr/chunk-77RZBIYQ.js:543:28) { code: 4002 }
问题原因
Express的路由匹配遵循从上到下的顺序:
- 现有代码中,
server.get('**', express.static(...))这个通配路由先被定义,它会匹配所有GET请求,包括/api/test。 - 由于静态资源中不存在
/api/test对应的文件,加上配置了index: 'index.html',该路由会返回Angular的入口文件index.html。 - 请求随后被后面的Angular SSR渲染路由接手,Angular尝试在自身路由表中匹配
api/test,最终因无对应路由抛出NG04002错误。
解决方法
将API路由的定义移至所有通配路由之前,确保Express优先匹配具体的API路径:
修改后的关键代码片段:
export function app(): express.Express { const server = express(); // ... 其他初始化代码 // 1. 先定义API路由 server.get('/api/test', function(req, res){ console.log("test first") res.json({test:"test"}) }) // 2. 再处理静态文件服务 server.get('**', express.static(browserDistFolder, { maxAge: '1y', index: 'index.html', })); // 3. 最后处理Angular SSR渲染路由 server.get('**', (req, res, next) => { // ... 原有渲染逻辑 }); return server; }
额外注意点
- 若开发时使用Angular Dev Server(端口4200),需确保已配置代理规则,将
/api请求转发到Express服务器的端口(默认4000),否则请求不会到达Express。 - 所有API路由都应遵循"具体路由在前,通配路由在后"的原则,避免被静态文件或Angular渲染路由拦截。
内容的提问来源于stack exchange,提问作者peni4142
相关产品推荐
相关产品推荐

