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

使用子域中间件匹配客户端工作区 Node+Express多企业平台开发需求

实现Node.js + Express多企业子域名隔离平台方案

我来给你梳理一下在Node.js + Express环境下实现多企业子域名专属平台的完整方案,从开发调试到部署落地都覆盖到:

1. 先搞定域名配置(线上+本地调试)

线上环境

你需要在域名服务商那里配置泛域名解析,把*.yourdomain.com指向你的服务器IP(或者负载均衡地址)。这样所有以企业标识开头的子域名(比如companyA.yourdomain.com、companyB.yourdomain.com)都会路由到你的服务器。

本地开发调试

为了在本地测试子域名功能,你需要修改系统的hosts文件:

  • Windows:C:\Windows\System32\drivers\etc\hosts
  • macOS/Linux:/etc/hosts

添加类似这样的条目:

127.0.0.1 companyA.localhost
127.0.0.1 companyB.localhost

这样访问companyA.localhost:3000就可以模拟线上的子域名请求了。

2. Express子域名解析实现

这里有两种常用方式,选你觉得顺手的就行:

方式一:用现成的express-subdomain中间件

这是最省心的方式,专门处理子域名路由:

  1. 先安装依赖:
npm install express-subdomain --save
  1. 编写核心代码:
const express = require('express');
const subdomain = require('express-subdomain');
const app = express();

// 定义企业专属路由的处理逻辑
const companyRouter = express.Router();

// 子域名预处理中间件:提取企业标识并验证
companyRouter.use((req, res, next) => {
  // 从子域名数组里取第一个元素(比如companyA.localhost的子域名是['companyA'])
  const companyId = req.subdomains[0];
  
  // 这里一定要加企业存在性验证!防止恶意子域名请求
  // 示例:假设你有个checkCompanyExists函数查询数据库
  // if (!await checkCompanyExists(companyId)) {
  //   return res.status(404).send('企业不存在');
  // }
  
  // 把企业ID挂载到req对象,后续所有路由都能直接用
  req.companyId = companyId;
  next();
});

// 企业专属接口示例
companyRouter.get('/', (req, res) => {
  res.send(`欢迎访问${req.companyId}的专属平台!`);
});

companyRouter.get('/orders', (req, res) => {
  // 这里查询数据库时自动带上req.companyId,实现数据隔离
  // const orders = await getOrdersByCompanyId(req.companyId);
  res.send(`${req.companyId}的订单列表`);
});

// 注册子域名路由:*匹配所有子域名
app.use(subdomain('*', companyRouter));

// 主域名路由(比如yourdomain.com或localhost)
app.get('/', (req, res) => {
  res.send('欢迎来到主平台首页!');
});

app.listen(3000, () => {
  console.log('服务器运行在http://localhost:3000');
});

方式二:自己编写子域名解析中间件

如果你不想依赖第三方包,也可以自己实现解析逻辑:

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

// 自定义子域名解析中间件
app.use((req, res, next) => {
  const host = req.get('host');
  // 拆分域名,处理带端口的情况(比如companyA.localhost:3000)
  const hostParts = host.split(':')[0].split('.');
  
  let companyId = null;
  // 判断是否是子域名请求:比如localhost环境下是3段(companyA.localhost),线上是3段以上(companyA.yourdomain.com)
  if (hostParts.length >= 2 && (hostParts[1] !== 'com' || hostParts.length > 2)) {
    companyId = hostParts[0];
  }
  
  // 同样要加企业验证逻辑
  req.companyId = companyId;
  next();
});

// 路由里根据companyId区分处理
app.get('/', (req, res) => {
  if (req.companyId) {
    res.send(`欢迎访问${req.companyId}的专属平台!`);
  } else {
    res.send('主平台首页');
  }
});

app.get('/data', (req, res) => {
  if (!req.companyId) {
    return res.status(403).send('请通过企业子域名访问');
  }
  // 业务逻辑:用req.companyId过滤数据
  res.send(`${req.companyId}的专属数据`);
});

app.listen(3000);

3. 数据隔离的核心注意事项

  • 数据库层面强制过滤:所有企业相关的数据表都要加company_id字段,所有查询、更新、删除操作必须带上company_id = req.companyId的条件,最好封装成数据库工具函数,避免开发者遗漏
  • 权限验证前置:在子域名中间件里必须验证企业的合法性,防止攻击者用随机子域名访问系统
  • 静态资源隔离:如果企业有自定义的静态资源(比如logo、样式),可以按企业ID分目录存储,比如public/companyA/logo.png,然后通过路由返回对应资源
  • 避免全局状态污染:不要用全局变量存储企业相关数据,所有数据都要通过req.companyId动态获取

4. 部署阶段的关键配置

Nginx反向代理配置

如果用Nginx做反向代理,必须确保传递Host头,否则Express拿不到正确的子域名:

server {
  listen 80;
  server_name *.yourdomain.com yourdomain.com;

  location / {
    proxy_pass http://localhost:3000;
    proxy_set_header Host $host; # 这行必须加!
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

HTTPS配置

要申请泛域名SSL证书(比如*.yourdomain.com),这样所有子域名都能使用HTTPS。Nginx的HTTPS配置示例:

server {
  listen 443 ssl;
  server_name *.yourdomain.com yourdomain.com;

  ssl_certificate /path/to/your/fullchain.pem;
  ssl_certificate_key /path/to/your/privkey.pem;

  location / {
    proxy_pass http://localhost:3000;
    proxy_set_header Host $host;
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:03:41