通过路由模块(@nuxtjs/router)实现不同域名访问不同页面,不需要代理服务器。
本文是对文章 How to handle multiple domains and subdomains in your Nuxt.js project 的整理与扩充。原文章简单地介绍了实现方法,但不够详细,代码也存在死板与冗余。本文将说明原理,并提供通用解。
为急性子直接提供解决方案 详细解释在后文
首先,安装"@nuxtjs/router",保存为开发用模块:
npm install --save-dev @nuxtjs/router
在/nuxt.config.js
中引入:
buildModules: [
// 实际项目中可能不仅仅@nuxtjs/router模块,此处为示例
[
'@nuxtjs/router',
{
path: 'router',
fileName: 'index.js',
keepDefaultRouter: true,
},
],
],
上方引入代码中path
和fileName
项指明了路由配置文件。在项目目录下建立/router/index.js
文件。
文件内容:
import Vue from "vue";
import Router from "vue-router";
Vue.use(Router);
export function createRouter(ssrContext, createDefaultRouter, routerOptions) {
const options = routerOptions || createDefaultRouter(ssrContext).options;
let hostname = ssrContext ? ssrContext.req.headers.host : location.host;
let group = /^([\w\.]+)(:\d+)?$/.exec(hostname);
let domain = group ? group[1] : "";
domain = doname.toLowerCase();
return new Router({
...options,
routes: formatRoutes(options.routes, domain)
});
}
function formatRoutes(defaultRoutes, domain) {
let routes = [];
defaultRoutes.forEach(route => {
if (!RegExp(`^\/${domain.replace(/\./, '\\.')}($|\\/.*)`).test(route.path))
return;
route.path = route.path.replace(new RegExp(`^\\/${domain}\\/?`), "/");
routes.push(route);
});
return routes;
}
接下来只需要在/page
文件夹下建立域名文件夹,以域名文件夹为域名对应根目录即可。
注意:域名是大小写无关的,但本文以小写形式匹配,因此域名文件夹需要全小写,否则无法正确匹配。
项目结构(此处仅展示改动部分,以实际项目为准):
project_root_dir
├── nuxt.config.js
├── package.json
├── pages
│ ├── a.b.chongying.studio
│ │ └── index.vue
│ ├── chongying.studio
│ │ └── index.vue
│ ├── other.chongying.club
│ │ └── index.vue
│ └── test.chongying.studio
│ └── index.vue
└── router
└── index.js
接下来是详细解释
不过,需要说明的也就只有两个函数。
创建路由函数(createRouter):
通过调用默认方法来生成基础的路由,并将生成的路由交给格式化路由函数作进一步处理。
export function createRouter(ssrContext, createDefaultRouter, routerOptions) {
// 获取默认的路由和主机名
const options = routerOptions || createDefaultRouter(ssrContext).options;
let hostname = ssrContext ? ssrContext.req.headers.host : location.host;
// 使用正则提取主机名中不带端口的部分 即所需的域名
let group = /^([\w\.]+)(:\d+)?$/.exec(hostname);
let domain = group ? group[1] : "";
// 转换为小写
domain = domain.toLowerCase();
return new Router({
...options,
routes: formatRoutes(options.routes, domain)
});
}
格式化路由函数(formatRoutes):
对默认路由进行筛选和处理。
function formatRoutes(defaultRoutes, domain) {
let routes = [];
defaultRoutes.forEach(route => {
// 筛除 非此域名的路由
if (!RegExp(`^\/${domain.replace(/\./, '\\.')}($|\\/.*)`).test(route.path))
return;
// 将路由路径的域名部分清除
route.path = route.path.replace(new RegExp(`^\\/${domain}\\/?`), "/");
routes.push(route);
});
return routes;
}
例如,存在以下路由:
/abc.chongying.studio
/abc.chongying.studio/abc
/abc.chongying.studio/abc/word
/def.chongying.club
/def.chongying.club/def
/def.chongying.club/def/word
当用户以’abc.chongying.studio访问时,路由将被处理为:
/
/abc
/abc/word
保留路径以"/abc.chongying.studio"开始的路由,并将路径中这部分前缀删除,即可得到正确的路由。