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

多子域Angular SSR项目架构合理性及实现方法咨询

架构方案可行性分析

你的子域分离Web应用与API的方案完全可行,这是前后端分离+多应用场景下的标准实践,核心优势包括:

  • 职责清晰:API专注数据服务,Web应用聚焦UI渲染与用户交互
  • 隔离性强:各Web应用可独立部署、迭代,互不干扰
  • 扩展性好:新增Web应用仅需添加对应子域配置即可
  • 跨域问题可通过CORS配置轻松解决
多应用SSR实现方案

结合你给出的项目结构,推荐基于Express为每个Web应用独立搭建SSR服务,同时统一API入口,具体实现步骤如下:

1. 优化项目结构(可选但推荐)

在每个Web应用目录下新增SSR服务代码,保持结构模块化:

my-app/
├─ web/
│  ├─ user/
│  │  ├─ src/          # 用户应用前端代码(React/Vue等)
│  │  ├─ server.js     # 用户应用SSR服务入口
│  ├─ public/
│  │  ├─ src/
│  │  ├─ server.js
│  ├─ store/
│  │  ├─ src/
│  │  ├─ server.js     # 支持通配符子域的SSR服务
├─ api/
│  ├─ index.js         # API服务入口
│  ├─ routes/          # 各业务路由模块
│  ├─ middleware/      # 认证、日志等中间件

2. 单个Web应用的SSR实现(以React为例)

以user.domain.com为例,核心流程是Express服务接收请求→调用API获取数据→渲染前端组件为HTML返回:

  • 第一步:编写SSR服务入口(web/user/server.js)
    const express = require('express');
    const React = require('react');
    const { renderToString } = require('react-dom/server');
    const App = require('./src/App').default;
    const app = express();
    
    // 处理所有GET请求
    app.get('*', async (req, res) => {
      // 1. 调用api.domain.com获取页面数据
      const apiRes = await fetch(`https://api.domain.com/user${req.path}`);
      const pageData = await apiRes.json();
    
      // 2. 将React组件渲染为HTML字符串
      const appHtml = renderToString(<App data={pageData} />);
    
      // 3. 拼接完整HTML(包含社交分享meta标签)
      const html = `
        <!DOCTYPE html>
        <html>
          <head>
            <title>用户中心</title>
            <meta property="og:title" content="${pageData.title}" />
            <meta property="og:description" content="${pageData.desc}" />
            <meta property="og:image" content="${pageData.image}" />
          </head>
          <body>
            <div id="root">${appHtml}</div>
            <!-- 加载客户端JS完成交互激活(hydration) -->
            <script src="/static/client.js"></script>
          </body>
        </html>
      `;
      res.send(html);
    });
    
    app.listen(3001, () => console.log('User SSR服务运行在端口3001'));
    
  • 第二步:打包客户端代码,用于浏览器端激活页面交互
  • 第三步:配置反向代理(如Nginx),将user.domain.com的请求转发到该Express服务

3. 通配符子域的Store应用SSR实现

针对*.domain.com(对应store-id),需在服务和代理层做额外配置:

  • Express服务中解析store-id:
    app.get('*', async (req, res) => {
      // 从请求头解析子域中的store-id
      const host = req.get('host');
      const storeId = host.split('.')[0];
    
      // 调用API获取对应店铺数据
      const apiRes = await fetch(`https://api.domain.com/store/${storeId}${req.path}`);
      const pageData = await apiRes.json();
    
      // 后续渲染逻辑同其他应用...
    });
    
  • Nginx配置通配符子域转发:
    server {
      listen 80;
      server_name *.domain.com;
    
      location / {
        proxy_pass http://localhost:3002; # Store SSR服务端口
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
      }
    }
    

4. API服务的CORS配置

由于Web应用与API属于不同子域,需在api/index.js中配置CORS允许合法子域访问:

const express = require('express');
const cors = require('cors');
const app = express();

// 允许的Web应用子域列表
const allowedOrigins = [
  'https://www.domain.com',
  'https://user.domain.com',
  'https://*.domain.com'
];

app.use(cors({
  origin: function(origin, callback) {
    if (!origin || allowedOrigins.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error('CORS限制:该来源不允许访问'));
    }
  },
  credentials: true // 若需携带cookie等凭证则开启
}));

// 配置API路由...
app.listen(3000, () => console.log('API服务运行在端口3000'));

内容的提问来源于stack exchange,提问作者1baz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 08:25:17