使用vhost+Node.js/Express如何实现用户注册后自动生成对应用户名的子域名
解决方案
核心思路
不需要提前为每个用户手动注册vhost规则,改用通配符匹配所有子域名,请求时动态提取子域名(即用户名)校验有效性即可,服务运行期间新注册的用户无需重启服务就能直接使用对应的子域名。
具体调整步骤
- 替换固定子域名的vhost规则为通配符匹配规则,提取子域名参数
- 新增子域名有效性校验中间件,请求时自动校验子域名对应用户是否已注册
- 复用原有子域名路由逻辑,无需为每个用户单独创建express实例
修改后完整代码
const express = require("express"); const app = express(); const morgan = require("morgan"); var cookieParser = require("cookie-parser"); const vhost = require("vhost"); const cors = require("cors"); const bodyParser = require("body-parser"); // 引入你的用户模型,用于校验用户是否存在 const UserModel = require("./api/models/user"); const institute_adminRoutes = require("./api/routes/institute-admin"); const domain = "localhost"; app.use(cors({ origin: "*", credentials: true, exposedHeaders: ["set-cookie"] })); app.use(cookieParser()); app.use(morgan("dev")); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); const subdomainApp = express(); subdomainApp.use(cookieParser()); subdomainApp.use(morgan("dev")); subdomainApp.use(bodyParser.urlencoded({ extended: false })); subdomainApp.use(bodyParser.json()); // 子域名校验中间件,每次子域名请求都会先执行 subdomainApp.use(async (req, res, next) => { // 提取子域名,也就是用户名 const username = req.vhost[0]; // 特殊处理不需要绑定用户的子域名,比如www、admin等,根据自己需求调整 if (["www", "admin"].includes(username)) { return next(); } // 查询数据库判断对应用户是否存在 const existUser = await UserModel.findOne({ username: username }); if (!existUser) { return res.status(404).json({ error: "该子域名对应用户不存在" }); } // 把用户信息挂载到req上,后续路由可以直接使用 req.subdomainUser = existUser; next(); }); // 绑定子域名路由 subdomainApp.use(institute_adminRoutes); // 通配符匹配所有子域名,替换原来的固定jhon子域名规则 app.use(vhost(`*.${domain}`, subdomainApp)); app.use("*", (req, res, next) => { const error = new Error("Not found"); error.status = 404; next(error); }); app.use((error, req, res, next) => { res.status(error.status || 500); res.json({ error: { message: error.message, }, }); }); module.exports = app;
注意事项
- 本地测试时需要在系统hosts文件中添加测试域名映射,比如测试用户为alice,需要添加
127.0.0.1 alice.localhost - 生产环境需要在域名服务商处配置泛域名解析,将
*.你的主域名解析到你的服务器IP - 如果需要限制子域名格式(比如不能包含特殊字符),可以在用户注册逻辑中提前校验用户名格式,避免生成非法子域名
内容的提问来源于stack exchange,提问作者Tony George
相关产品推荐
相关产品推荐

