多子域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
相关产品推荐
相关产品推荐

