单域名下同时部署多个版本的单页应用

什么是单页应用?

单页应用是一种网络应用程序或网站的模型,服务端返回单个html文件,页面的切换不再请求新的html文件,而是直接在用户端异步获取新页面数据并在用户端进行新页面的绘制。

单域名下发布与管理多版本

意思就是在同一个域名下同时部署同个网站的多个版本的代码,同时提供对于多个版本网站的切换与访问方式。
这种技术多用于QA测试环境,比如在同一个测试域名下部署多个分支的代码,提供多套QA测试环境。

本实现方案是一个在单域名下发布与管理多个版本单页应用的一种解决办法。
其最初目的就是为了解决在同一个域名下部署多套QA环境的部署问题。
因此本文介绍此方案也是围绕这个目的来进行。

一、原多域名QA环境部署方案介绍

我们部门有自己的Devops自动化部署系统,该系统能自动监听git提交事件触发代码的构建。
同时,也将“Tapd”需求系统与代码分支进行了关联,只需要将对应需求的git分支名、测试域名填入需求单里面,就可以做到‘需求-代码-部署’的全自动化流转。
做到了每一个需求都拥有自己特有的运行与测试环境,拥有独立的测试域名。
比如:https://qa1.epoos.com、https://qa2.epoos.com、...、https://qaN.epoos.com。
独立域名使用起来还是很方便的,但是方便的背后也有着其局限性。
其主要问题就是“域名数量是有限的”
为了解决域名限制的问题,我们已经对域名扩增了多次,最多的时候申请和配置了30+个,到了qa30.epoos.com。
然而,并没有解决根本问题,随着时间的推移,开发人员扩招、业务扩大,需求增加,以及域名释放机制的不合理等等原因,最终域名还是出现了不够用的情况。

很显然,一味的扩充域名并不能一劳永逸的解决问题,虽然只是二级域名但是数量多了以后还是需要一些维护成本的。
要想从根本上解决问题,只能想其它的办法。经过与组内大佬的讨论,最终定下了一个解决方案。

二、单域名解决方案

经过多轮讨论与调研,发现此方案是完全可行的。
single-domain

整套解决方案共分为三部分:发布部署、网关与网关函数设置、用户端环境切换设置。

代码部署:

通过文件上传、拷贝、或者网络同步的方式将需要部署的代码包部署到服务器上,每一个代码包都有自己唯一的文件夹名称,如上图文件服务器上的version1 文件夹。
每一个版本的代码包拥有唯一独立的文件夹名称,可以直接用版本号、代码分支名等作为其名称。
因为其是单页应用(我们默认静态资源js、css、image走了cdn部署),所以这里服务器文件夹下面每一个代码文件包其实仅仅只包含一个index.html文件,因此只需要一台服务器就足够部署成千上万个版本的代码包了。

网关与网关函数组件:

网关端配置,拦截页面请求,将其转发到网关函数,网关函数获取请求信息中携带的cookie信息中的页面版本信息,根据版本信息查询到该版本对应的服务器上页面所在的唯一文件夹名称。
并返回返回该版本的文件内容。
我们的这套解决方案是单域名的,只有一个域名,因此也只有一个网关配置(网关的实现方案有很多可以是Nginx、也可以是其它),我们的QA环境走的是腾讯云的网关云服务,云服务支持配置网关函数,也就是说我们给该域名的请求转发到网关云函数。
其核心代码如下如所示
single-domain-code
此云函数的作用就是取得页面请求中携带的版本信息,然后根据版本信息从我们的代码部署服务器上找到对应的版本文件夹下的index.html文件,然后将其返回给用户端浏览器。
请求携带的版本信息支持请求查询参数和cookie两种,如果是查询参数中获取的,那么返回index.html的时候主动将其版本信息写入用户端cookie里面(原因见用户端版本设置组件)。

用户端版本设置组件:

版本设置组件可以有多种实现,其目的为给用户提供版本设置功能,并将其设置存储在本地cookie。
之后发起页面请求的时候版本信息就会作为请求中携带的cookie传入网关。
实现方式1)单独的设置页面,为网站单独设置一个设置地址url,在此url下面可设置版本信息,并存入cookie。
single-domain-setpage
实现方式2)页面内部嵌入插件,此插件可收缩和隐藏,需要设置的时候将其展开,展开之后可设置版本信息,并存入cookie。
实现方式3)直接在页面请求中加入版本设置的特殊参数,配合网关函数使用,网关函数检测到url后面的版本信息之后自动将其作为版本信息返回,并写入cookie。
single-domain-set

上面三种方法为用户指定请求页面的版本提供了入口,只需要提前知道了想要访问的代码版本就能够进行设置。
而实现方式3是一种无感知的快捷设置方式,需要网关函数配合,接收到请求版本信息之后将信息会写入响应的cookie中。

以上,就是我们新的部署实现方案,一种单个域名下部署和管理多个版本单页应用的实现方案。
新的部署方案只需要一个域名、一个api网关服务、一台服务器即可实现无限个QA环境的部署,每个版本只有一个index.html的代码,大小也就几kb到几十kb理论上一台服务可以部署无限个版本的网站应用,再也不需要为了环境资源而烦恼了。

三、扩展

上面所说的都是基于特定环境进行的部署,比如使用的是腾讯云网关服务,使用的是自动化部署流程。
如果脱离了上述环境体系,这一套流程还能使用吗?
当然可以,下面我们来说道说道。

1.精简版环境搭建

首先,咱们来理一理,什么是发布?
发布的其实就是将我们的代码部署到服务器上,然后对外暴露一个域名。

我们完全可以自己搭建一套简单的部署方案。
只需要一个业务域名 + 一个cdn域名 + 一个网关 + 一台服务器就能搞定。
材料准备:一个页面域名page.example.com + 一个cdn域名cdn.example.com + 一台服务器C

详情如下图所示。
single-domain-samp

1
2
3
4
1.本地代码构建,生成一个源代码 dist 目录
2.通过 scp/rsync或者手动拷贝 的方式将dist目录的代码部署在服务器C下的某个目录下,其中静态资源和index.html可以部署在一起也可以分开目录部署.
3.将页面域名 page.example.com 和 cdn.example.com 做DNS解析到服务器C(直接在域名服务商那里配置即可)
4.在服务器C上做一个网关转发如(Nginx ),nginx将page.example.com请求转发到index.html目录下,将cdn.example.com域名转发到静态资源的目录下(API网关请求转发)

进行如上部署之后,我们的应用就相当于部署完成了,接下来访问 page.example.com 就行了,如此简单。

当然,如果需要实现更复杂的请求转发规则,单纯的使用Nginx做起来很麻烦,最简单灵活的方法就是

1
2
1.在服务器C上启一个nodejs服务D
2.nginx将所有的请求都转发到服务D上,Node服务D再根据请求的路径和参数将请求再次路由到不同的文件目录或者其他服务,(这就是我们的网关函数)

2.精简版改造成单域名环境

前面第1步我们搭建了一个简易版的单页应用服务器环境。
想要在此基础上支持单域名多版本管理,只需要进行简单的改造。
我们从前文中单域名方案的实现介绍可以知道,其实现主要三个部分:多版本部署、网关转发、前端版本变量设置。
多版本部署即将多个版本分别部署在服务器的不同文件夹下面,对于我们的精简版环境的服务器,其实就是在scp/rsync 拷贝代码的时候将其不同版本的代码拷贝在服务器C的不同文件夹下。
网关转发即在nginx或者nodejs服务D上拦截页面请求,获取cookie或者请求参数的版本信息,然后根据其信息从上面部署的代码里面找到对应的index.html文件的代码并返回。
前端版本设置即想办法将环境版本信息写入页面的cookie中,可以使用前面的三种方式,也可以使用其它方式。

以上就是整个单域名下不是和管理多套单域名网页应用环境的实现与原理。