前端测试环境多泳道部署方案
1. 安装和启动 nginx:
安装 nginx,一般有两种方式:
- 直接安装和启动 nginx
- 利用 docker 安装nginx的镜像,启动 nginx 容器。
由于我们本次聚焦于nginx相关的内容,所以我们采用直接安装和启动nginx进行测试。另外具体的nginx的安装和启动的教程,我们在这里就不再赘述了。我本机已经提前安装和启动了nginx,并且,本机的nginx监听的是80端口,所以当nginx启动之后,我们就可以直接访问 80 端口来访问 nginx 服务了:
常见的前端项目部署和访问流程:
通常情况下的前端项目的部署和访问流程比较简单:
一般前端项目的通用部署流程:
一般前端项目的通用访问流程:
举一个简单的例子:
我们在本地准备了一个简单的前端项目:
此时就表示我们的开发和和项目构建已经完成,并且将其部署到了静态资源服务器中的 default 文件夹下面。并且前端静态资源服务器的地址是:
js
http://192.168.1.8:5500
我们给当前的前端项目绑定一个域名:
arduino
http://localhost:80
我们期望当我们在浏览器中输入: http://localhost:80/ 之后就可以成功访问到前端静态资源并且成功渲染出页面。 因为我们是在本地进行测试,所以,我们本地的nginx服务对应的服务ip是:127.0.1。 而默认情况下,本机的 localhost 域名经过域名解析之后就是 127.0.1,所以域名解析已经ok了。我们想要通过 nginx 能够处理 http://localhost:80/ 这个请求,只需要在 nginx 中配置域名和端口对应的 server 规则就可以了,因此,我们在nginx中加入了如下的配置:
nginx
server {
# 处理 http://127.0.0.1:80 | http://localhost:80 请求
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
# 将其代理到 http://192.168.1.8:5500/default/
proxy_pass http://192.168.1.8:5500/default/;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
以上配置也使得,当我们访问 http://localhost/ nginx的处理逻辑如下:
我们可以重启以下nginx服务,然后访问 http://localhost/ 可以看到如下效果:
为了更加清晰的探究 nginx 代理转发的原理,我们可以查看以下当前页面访问的网络请求的状况:
我们可以看到主要的网络请求一共是三个:
首先请求 http://localhost/
这个请求会被 nginx 拦截到,然后代理到了 http://192.168.1.8:5500/default/ 拿到了 html 的响应结果:
紧接着浏览器会启动渲染进程中的 html 解析器解析html。不过在文本正式解析之前,渲染进程会利用预解析线程去请求 html 中引用到的所有的 css 以及 js 的文件。所以我们就可以看到 index.css 以及 index.js 两个静态资源文件的请求。只不过因为我们在 html 中是直接通过相对路径的方式去引用资源文件,所以,浏览器会发送如下两个请求:
http://localhost/index.css http://localhost/index.js
这两个请求同样会被 location / 这个路由规则拦截到,并且代理为如下两个请求进行处理:
http://192.168.1.8:5500/default/index.css http://192.168.1.8:5500/default/index.js
从而拿到了所有的静态资源:
最终完成了页面的渲染。
以上就是基于 nginx 的前端应用的配置和访问流程,其实还是比较容易理解的。
理解前端多泳道发布:
多泳道发布一般是上了一定规模的前端团队才可能接触到的前端部署方式。 它的最终目的就是在前端测试环境可以一次性部署多个前端版本,QA可以访问和测试指定的前端版本。 比如目前前端已经创建了两个前端多泳道: gray1 gray2 那么在部署的时候,我们就可以选择将指定版本的前端资源部署到特定的泳道中去。在部署的过程中,前端流水线会先在静态资源服务上创建出指定的泳道名对应的资源文件夹,然后将指定版本对应的资源文件上传到该文件夹中。 当泳道部署完之后,前端静态资源的情况就类似于下面这样:
不同泳道之间的前端资源相互隔离,内容可能会有很大的差异,从而 QA 可以访问不同泳道的资源,进行AB test。
访问时带上泳道标记:
我们默认通过域名去访问前端页面的时候,永远都只会访问到默认泳道的资源,为了能够访问指定泳道的资源,我们可以在请求头中加上泳道标记,明确的告诉 nginx 我们需要访问哪个泳道的资源,为此我们可以使用一个浏览器插件:
在指定的域名下加上泳道标记:
保存之后,当我们再次访问:http://localhost/ ,我们就可以看到:
请求已经带上了泳道标记了。
nginx 根据泳道标记进行请求转发:
众所周知,nginx 配置文件是很强大的,可以像一些编程语言一样定义变量以及编写一些逻辑判断的语句,基于这一点,我们可以根据请求头中的泳道标记来动态的设置最终的代理和转发的地址,将请求转发的指定的泳道中,基于此,我们更改 location / 的处理逻辑:
nginx
location / {
# 从 http 请求头中获取 x_Gray 头,也就是泳道标记
set $gray $http_X_Gray;
# 默认访问 base 泳道
set $lane 'default';
if ($gray) {
# 如果用户指定了泳道
set $lane $gray;
}
proxy_pass http://192.168.1.8:5500/$lane;
}
更改配置之后,我们重启 nginx,然后尝试访问不同泳道的资源: 我们输入url http://localhost/ 看一下请求头:
此时请求头中带上了泳道2的标记:
此时的页面:
不太正确啊,html确实是泳道2的内容,但是css好像不对啊。我们查看类名:
类名也没有成功加上去,说明js和css好像都不正确。我们看一下网络:
what?为什么js和css文件返回的都是html的内容?好诡异啊。 要分析出这个问题的原因,我们还得回到现在 nginx 的配置中去: 我们首先来分析一下请求 html 和 请求js/css之间请求地址的区别:
/
/index.css
/index.js
拼接上泳道标记之后,再经过nginx代理之后,nginx层最终的请求地址应该是:
http://192.168.1.8:5500/gray2/
http://192.168.1.8:5500/gray2/index.css
http://192.168.1.8:5500/gray2/index.js
但是此时因为我们在最终的 proxy_pass 配置中加上了变量,那么情况就会有所差异了: 我们对比一下两种情况:
proxy_pass http://192.168.1.8:5500/gray2/;
proxy_pass http://192.168.1.8:5500/$line;
如果我们是按照第一种配置将代理地址写死的话,那么 nginx在代理的时候就会对比一下请求的uri 和 location / 的差异,并且将多余的地址和参数,直接拼接在 proxy_pass 的后面,然后再去进行转发: 也就是当我们请求 http://localhost/index.css 的时候,nginx 对比 /index.css 和 / 发现此时的请求多出了 index.css,那么它就会将其直接拼接在代理地址的后面,也就是:
http://192.168.1.8:5500/gray2/ + 'index.css'
最终会正确的请求到: http://192.168.1.8:5500/gray2/index.css
但是如果我们最后写的是变量,那么此时nginx就只会将 $line 对应的值原地替换,而不会再进行额外的操作。也就是nginx最终请求的地址永远是: http://192.168.1.8:5500/gray2/ 这也就是请求 js 以及 css 文件,nginx 的返回结果是 html 内容的原因。 那么要解决这个问题,我们需要对代理地址进行如下的改动:
proxy_pass proxy_pass http://192.168.1.8:5500/$line$uri;
我们在变量的后面还加上了一个内置变量 $uri 这个变量的值是我们发起请求的地址的uri:
http://localhost/index.css ---> uri: /index.css
nginx 最终就可以拼接产生正确的请求地址了。
这样调整之后,我们再次访问泳道2的内容:
访问泳道1的内容
访问默认泳道的内容,(注意: 这个时候需要将设置泳道请求头的规则关闭掉):
以上泳道都可以正常访问了。
结语和预告:
至此,我们就完整的探讨了前端测试环境多泳的部署实现方案,如果后续读者们感兴趣,我们会继续更新前端 node.js 的多泳道的实现方案。