You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的路由匹配遵循从上到下的顺序:

  1. 现有代码中,server.get('**', express.static(...))这个通配路由先被定义,它会匹配所有GET请求,包括/api/test。
  2. 由于静态资源中不存在/api/test对应的文件,加上配置了index: 'index.html',该路由会返回Angular的入口文件index.html。
  3. 请求随后被后面的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 21:58:08