域名驱动多租户入驻:后台配置 + 前端解析

域名驱动多租户入驻:后台配置 + 前端解析

摘要 :线上租户以访问域名为准,机构与域名的绑定在后台维护;前端在启动阶段用当前域名请求 getByDomain 解析机构信息等,写入会话并在后续请求携带 机构信息。src/tenant 与构建变量承担可选白标定制,与域名租户上下文分层,不宜混写成「一租户一构建产物」。


一、先分清两件事

多租户常被说成「一套代码服务很多家机构」。在本项目里,建议拆成两层理解:

层次 回答的问题 谁配置 前端落点
业务租户(域名) 当前访问的是哪家机构 后台维护域名与机构关系 getByDomain机构信息 → 请求头
前端白标包(可选) 页面品牌、路由、权限、主题是否与标准版不同 工程侧 src/tenant/*、构建变量 loadTenantConfig@tenant 资源

入驻的主线是:后台开通机构并绑定域名 → 用户用该域名访问 → 前端解析机构上下文 → 业务接口按租户隔离。
createOrg.js、多租户构建脚本属于「新机构要深定制页面时」的工程补充,不能替代后台域名配置。

build/tenant-domain-map.js 租户身份在构建期由 VITE_TENANT_ID 参与白标构建;运行时「你是哪家机构」仍由域名 + 后台决定。


二、入驻在业务上包含什么

从「机构能对外服务」倒推,通常至少包括:

  1. 后台 :创建机构、分配 机构关键字段 / appId、绑定访问域名(可含测试域、正式域)。
  2. 前端运行时 :用当前域名换机构信息,并把 机构关键字段 带入后续 API。
  3. (可选)工程侧 :从 tenant-standard 脚手架出新租户目录,改 Logo、协议页、路由覆盖、权限开关;独立租户写入 independentTenants 等。

课程、订单、钱包等数据的租户隔离在后端;前端职责是稳定带上租户上下文,避免串租户。


三、运行时主链路:域名 → 机构 → 请求头

3.1 用域名换机构

店铺/机构信息通过半登录接口按域名查询,开发环境可用 VITE_APP_DOMAIN 模拟线上域名:

php 复制代码
export function getShopInfo(params) {
  return request({
    url: "/getByDomain",
    method: "get",
    params: {
       hostname:  window.location.hostname,
    },
  })
}

要点:

  • 生产以 window.location.hostname 为准。
  • 域名与机构的映射在后台维护,前端不写死映射表。
  • 接口路径带 semiLogin,与未登录也可访问的站点场景一致。

3.2 路由守卫里初始化店铺与 orgCode

应用启动后 initRouter 注册全局 beforeEach,在进页面前 await ensureShopInfo()。成功后将 机构关键字段 写入 sessionStorage(键与 configId 组合),并更新 Pinia:

864:876:d:/project/pro-a/src/router/index.js 复制代码
            try {
                shopStore.setLoading(true);
                const shopRes = await getShopInfo();
                if (shopRes && shopRes.data) {
                    sessionStorage.setItem('机构关键字段_'+sessionStorage.getItem('configId'), shopRes.data['机构关键字段信息']);
                    let shopInfo = {
                        ...shopRes.data
                    };
                    shopStore.setShopInfo(shopInfo);
                }

ensureShopInfo 有缓存:Pinia 已有店铺信息则不再请求;失败时可回退 localStorage 中的 shopId。新机构验收时要覆盖「域名已配、接口 200、首屏守卫执行」与「域名未配、接口失败」两类路径。

3.3 请求拦截器:把租户上下文带给后端

request 拦截器从 Cookie、sessionStorage 取 token 与 机构关键字段,写入 Authorization机构关键字段;并从租户配置取 x-app-id

csharp 复制代码
    let token = Cookies.get('t_'+sessionStorage.getItem('configId'))
    // ...
    if (token) {
        config.headers['Authorization'] = ''
    }
    let 机构关键字 = sessionStorage.getItem('机构关键字段_'+sessionStorage.getItem('configId')) || ''
    if (机构关键字段) {
      config.headers['机构关键字段'] = 机构关键字段值
    }
    // ...
    const tenantStore = useTenantStore();
    if (tenantStore.config && tenantStore.config.appInfo) {
        config.headers['x-app-id'] = tenantStore.config.appInfo.appId;
    }

configIdmain.js 里由租户配置的 appInfo.appId 写入 sessionStorage,用于隔离不同应用下的 token、机构关键字段 键名。同一前端包服务多域名时,域名解析出的 机构关键字段配置里的 appId 会共同构成请求上下文。


四、应用启动顺序(与白标配置并行)

main.js 中:创建应用 → initRouter(含上述守卫)→ initTenantConfig(站点 meta、主题、configId)→ initPermissions → 挂载。

ini 复制代码
    const router = await initRouter();
    app.use(router);
    const tenantConfig = await initTenantConfig(app);
    app.config.globalProperties.tenantConfig = tenantConfig;
    setGlobalConfig(tenantConfig);
    sessionStorage.setItem('configId', tenantConfig?.appInfo?.appId || '');
    await initPermissions();

域名租户白标配置 在启动阶段并行就绪:前者靠守卫拉机构,后者靠 loadTenantConfig 加载 src/tenant/<id>/config/index.js(构建期 VITE_TENANT_ID 决定加载哪一份)。缺配置文件会直接报错,与「域名是否已在后台绑定」是两类问题。


五、工程侧入驻:createOrg 与白标目录

需要新机构独立品牌资源、协议、路由 时,可用根目录 createOrg.js:创建 src/tenant/<tenantId>/,从 tenant-standard 复制图片、permissions.jsassets/public,生成 config/index.js;若选独立租户,写入 build/tenant-domain-map.jsindependentTenants

脚本不会 自动改 package.json 或后台域名,README 要求手动增加 dev:tenant-xxx / build:tenant-xxx,并在后台完成域名绑定。

租户路由通过 name 覆盖平台路由,并合并 beforeEnter,避免换组件时丢掉平台守卫(详见 router/index.jsinitRouter 合并逻辑)。权限来自各租户 assets/js/permissions.js,由 hasPermission 做点路径判断。


六、开发 / 生产差异

场景 域名来源 注意
生产 用户访问的 hostname 后台域名与机构一致
本地 VITE_APP_DOMAIN 或本机 host 模拟线上域名,否则 getByDomain 可能对不上
白标构建 VITE_TENANT_ID 决定打进产物的 config、静态资源、@tenant 别名

线上「多域名、一套前端」依赖后台域名表 + 前端 getByDomain ;深定制可再出多份带不同 VITE_TENANT_ID 的构建产物,二者可组合,但不是同一概念。


七、端到端流程(入驻视角)

sequenceDiagram participant Admin as 后台配置 participant User as 用户浏览器 participant FE as 前端 participant API as api-c Admin->>Admin: 创建机构并绑定域名 User->>FE: 访问已绑定域名 FE->>API: getByDomain(domain) API-->>FE: orgCode机构信息等 FE->>FE: sessionStorage与Pinia User->>FE: 路由跳转 FE->>API: 业务请求带org-code等

八、验收清单(建议)

  1. 后台:机构、机构关键字段、域名(含测试域)已保存且生效。
  2. 用该域名访问:getByDomain 返回预期机构名与 机构关键字段
  3. 任意业务请求:请求头含 机构关键字段(及约定的 x-app-id)。
  4. 若走白标脚手架:config/index.js、协议静态页、权限与构建脚本可本地/预发验证。
  5. 异常:未绑定域名、接口失败时,页面与接口错误可感知,避免静默串到默认机构。

九、小结

多租户入驻的主线是域名在后台配置、前端按域名解析机构并贯穿请求链createOrgsrc/tenant 解决的是白标与工程交付。写方案或专栏时应用「域名租户」与「白标包」两层表述,避免与「单包单租户构建」混为一谈。

支付、分账、宝付监管、独立商户结算属订单与资金域,可在后续篇章单独写;本篇只界定前端在「租户识别」上的边界。

相关推荐
TeamDev1 小时前
在 Excel 加载项中嵌入 Web 视图
前端·后端·.net
悠哉摸鱼大王1 小时前
cesium学习(一)-基本概念
前端·cesium
LinDaiDai_霖呆呆1 小时前
大白话介绍大模型的一些底层原理,看完终于能跟人聊两句了
前端·人工智能·面试
悠哉摸鱼大王1 小时前
cesium学习(二)-地图地形
前端·cesium
青山师1 小时前
【AI热点资讯】5月10日AI热点:Cloudflare裁员1100人、Musk庭审第二周回顾、OpenAI发布Codex Chrome插件
前端·人工智能·chrome·ai·ai热点
阿赛工作室2 小时前
AI时代WEB开发人员生存与发展报告
前端·人工智能·node.js
用户125758524362 小时前
写了三年定时任务还在手改 Cron 表达式?这个 GoFrame 后台框架帮你全闭环了
vue.js
ZC跨境爬虫2 小时前
跟着 MDN 学 HTML day_36:(深入理解 Comment 接口与 DOM 注释节点)
前端·javascript·ui·html·音视频·视频编解码
石小石Orz3 小时前
Harness Engineering 到底是什么?概念、实战与争议,一次全部讲清楚
前端·后端