# 动静分离

动静分离有一个比较常用的功能这个功能比较适用于中小型的网站,因为中小型网站的并发量不是很高而且需要分离出来的资源不是很多,需要将这些静态资源移动到前置的 Nginx 里

为了提高网站的响应速度,减轻程序服务器 (Tomcat,Jboss 等) 的负载,对于静态资源,如图片,js,css 等文件,可以在反向代理服务器中进行缓存,这样浏览器在请求一个静态资源时,代理服务器就可以直接处理,而不用将请求转发给后端服务器,对于用户请求的动态文件,如 Servlet,jsp 则转发给 Tomcat,Jboss 服务器处理,这就是动静分离,即动态文件于静态文件的分离

# 使用动静分离的场景

image_2023-01-29-19-25-18

image_2023-01-30-19-17-18

动静分离可通过 location 对请求 url 进行匹配,将网站静态资源 (HTML,javaScript,CSS,img 等文件) 于后台应用分开部署,提高用户访问静态代码的速度,降低对后台应用访问,通常将静态资源放到 nginx 中,动态资源转发到 tomcat 服务器中

演示

0 号机 nginx 配置

server {
        listen       8080;
	
        server_name localhost;
        location / {
		#httpds随便起的别名,但是要与upstream对应得上,upstream和server是同一级别的
		proxy_pass http://192.168.244.139:8088;
		#root 只能查找本机中根目录的项目
            #root   http://www.qq.com;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
}

1 号机的配置如下:

server {
        listen       8088;
        server_name  localhost;

        location / {
	    proxy_pass http://192.168.244.139:8080/ngintestday28/web/;
	    #root /www;
            index  index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

}

1 号机中配置了 Tomcat

访问浏览器效果如下:

image_2023-01-30-13-48-12

将 1 号机中项目的静态文件删除

image_2023-01-30-13-49-42

刷新页面

image_2023-01-30-13-50-08

变成了原始的样式

配置反向代理服务器上静态资源

在 0 号机中配置如下:

 server {
        listen       8080;

        server_name localhost;
        location / {
                #httpds随便起的别名,但是要与upstream对应得上,upstream和server是同一级别的
                proxy_pass http://192.168.244.139:8088;
                #root 只能查找本机中根目录的项目
            #root   http://www.qq.com;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        #uri地址
        location /css {
            #root 只能查找本机中根目录的项目
            #不需要加额外的目录,在访问时会指向根路径然后顺便加上uri的地址同时拼接
            root   html;                                                                                                                                  
            index  index.html index.htm;
        }
}

在 0 号机的 html 目录下传输过去项目的 css 样式

image_2023-01-30-14-00-23

重启服务 systemctl restart nginx.service , 请求访问地址查看效果

image_2023-01-30-14-07-33

静态资源由 nginx 返回,主页由 tomcat 返回

剩下我们加上其它的样式代码

  • js
server {
        listen       8080;

        server_name localhost;
        location / {
                #httpds随便起的别名,但是要与upstream对应得上,upstream和server是同一级别的
                proxy_pass http://192.168.244.139:8088;
                #root 只能查找本机中根目录的项目
            #root   http://www.qq.com;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        #uri地址
        location /css {
            #root 只能查找本机中根目录的项目
            #不需要加额外的目录,在访问时会指向根路径然后顺便加上uri的地址同时拼接
            root   html;
            index  index.html index.htm;
        }

        #uri地址
        location /js {
            #root 只能查找本机中根目录的项目
            #不需要加额外的目录,在访问时会指向根路径然后顺便加上uri的地址同时拼接
            root   html;
            index  index.html index.htm;
        }                                                                                                                                                 
}

重启服务 systemctl restart nginx.service , 刷新页面查看效果

image_2023-01-30-14-11-35

可以看到 js 加载成功了

  • fonts
#uri地址
        location /fonts {
            #root 只能查找本机中根目录的项目                                                                                                              
            #不需要加额外的目录,在访问时会指向根路径然后顺便加上uri的地址同时拼接
            root   html;
            index  index.html index.htm;
        }

image_2023-01-30-14-12-50

  • img
#uri地址
        location /img {
            #root 只能查找本机中根目录的项目
            #不需要加额外的目录,在访问时会指向根路径然后顺便加上uri的地址同时拼接                                                                         
            root   html;
            index  index.html index.htm;
        }

image_2023-01-30-14-13-41

重启服务 systemctl restart nginx.service 刷新页面查看效果

image_2023-01-30-14-15-12

弊端:代码过多冗余度太大,下面为解决方式:使用正则表达式来解决问题

  • 正则规则:以~* 开始在小括号中写入 (x|x|x)

  • ~ 根目录任意:跟目录开始任意的地方

server {
        listen       8080;
	
        server_name localhost;
        location / {
		#httpds随便起的别名,但是要与upstream对应得上,upstream和server是同一级别的
		proxy_pass http://192.168.244.139:8088;
		#root 只能查找本机中根目录的项目
            #root   http://www.qq.com;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
	
	#正则中不区分大小写,使用格式:(x|x|x|x)
        location ~*/(js|css|img|fonts) {
	    root html;
            index  index.html index.htm;
        }
}
  • 重启服务后,刷新页面查看效果

image_2023-01-30-14-25-44

image_2023-01-30-14-26-23

正常访问

image_2023-01-30-14-45-45

使用正则配置动静分离

常见的 Nginx 正则表达式

^:匹配输入字符串的起始位置
$:匹配输入字符串的结束位置
*:匹配前面字符零次或多次.如"ol*"能匹配"o"及"ol","oll"
+:匹配前面的字符一次或多次.如"ol+"能匹配"ol"及"oll","olll"但不能匹配"o"
?:匹配前面的字符零次或一次.如"do(es)?"能匹配"do"或者"does","?"等效于"{0,1}"
.:匹配除"\n"之外的任何单个字符,诺要匹配包括"\n"在内的任意字符,请使用诸如"[.\n]"之类的模式
\:将后面接着的字符标记为一个特殊字符或一个原意字符或一个向后引用,如"\n"匹配一个换行符,而"\$"则匹配"$"
\d:匹配纯数字
{n}:重复n次
{n,}:重复n次或更多次
{n,m}重复n到m次
[]:定义匹配的字符范围
[c]:匹配单个字符c
[a-z]:匹配a-z小写字母的任意一个
[a-zA-Z0-9]:匹配所有大小写字母或数字
():表达式开始和结束位置
|:或运算符 //例如:(js|img|css)

location 正则:

//location大致可分为三类
精准匹配:location = /{}
一般匹配:location /{}
正则匹配: location ~/{}
//location常用的匹配规则
=:进行普通字符精准匹配,也即是完全匹配
^~:表示前缀字符串匹配(不是正则匹配,需要使用字符串),如果匹配成功,则不再匹配其它,location
~:区分大小写的匹配(需要用正则表达式)
~*:不区分大小写的匹配(需要使用正则表达式)
!~:区分大小写的匹配取非(需要使用正则表达式)
!~*:不区分大小写的匹配取非(需要使用正表达式)
//优先级
首先精准匹配 =
其次匹配前缀匹配 ^~
其次是按文件中顺序的正则匹配 ~或~*
然后匹配不带任何修饰的前缀匹配
最后是交给 / 通用匹配

注意

  • 精准匹配: = , 后面的表达式中写的是纯字符串

  • 字符串匹配: ^~ 和 字符串匹配 ,后面的表达式中写的是纯字符串

  • 正则匹配: 和! 和!, 后面的表达式中写的是正则表达式

 (1)location = / {}
=为精确匹配 / ,主机名后面不能带任何字符串,比如访问 / 和 /data,则 / 匹配,/data 不匹配
再比如 location = /abc,则只匹配/abc ,/abc/或 /abcd不匹配。若 location  /abc,则即匹配/abc 、/abcd/ 同时也匹配 /abc/。

(2)location / {}
因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求 比如访问 / 和 /data, 则 / 匹配, /data 也匹配,
但若后面是正则表达式会和最长字符串优先匹配(最长匹配)

(3)location /documents/ {}
匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索其它 location
只有其它 location后面的正则表达式没有匹配到时,才会采用这一条

(4)location /documents/abc {}
匹配任何以 /documents/abc 开头的地址,匹配符合以后,还要继续往下搜索其它 location
只有其它 location后面的正则表达式没有匹配到时,才会采用这一条

(5)location ^~ /images/ {}
匹配任何以 /images/ 开头的地址,匹配符合以后,停止往下搜索正则,采用这一条

(6)location ~* \.(gif|jpg|jpeg)$ {}
匹配所有以 gif、jpg或jpeg 结尾的请求
然而,所有请求 /images/ 下的图片会被 location ^~ /images/ 处理,因为 ^~ 的优先级更高,所以到达不了这一条正则

(7)location /images/abc {}
最长字符匹配到 /images/abc,优先级最低,继续往下搜索其它 location,会发现 ^~ 和 ~ 存在

(8)location ~ /images/abc {}
匹配以/images/abc 开头的,优先级次之,只有去掉 location ^~ /images/ 才会采用这一条

(9)location /images/abc/1.html {}
匹配/images/abc/1.html 文件,如果和正则 ~ /images/abc/1.html 相比,正则优先级更高

优先级总结:
(location =) > (location 完整路径) > (location ^~ 路径) > (location ~,~* 正则顺序) > (location 部分起始路径) > (location /)

实际网站使用中,至少有三个匹配规则定义:

  • 第一个匹配必选规则:

直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,比如说官网,这里是直接转发给后端应用服务器了,也可以是一个静态首页

location = / {
    proxy_pass http://127.0.0.1:8080/; 
}
  • 第二个必选规则:

处理静态文件请求,这是 nginx 作为 http 服务器的强项,有两种配置模式,目录匹配或后缀匹配,人选其一或搭配使用

location ^~ /static/ {
    root /webroot/static/;
}

location ~* \.(html|gif|jpg|jpeg|png|css|js|ico)$ {
    root /webroot/res/;
}
  • 第三个规则:

通用规则,用来转发动态请求到后端服务器

location /api/ {
    proxy_pass http://127.0.0.1:3000/api/
}

# URLRewrite

rewrite 是实现 URL 重写的关键指令,根据 regex (正则表达式) 部分内容,重定向到 repacement, 结尾是 flag 标记

格式:

rewrite <regex> <replacement> <flag>

关键字 正则 替代内容 标记

关键字:其中关键字 error_log 不能改变

正则:perl 兼容正则表达式语句进行规则匹配

替代内容:将正则匹配的内容替换成 replacement

flag 标记:rewrite 支持的 flag 标记

flag 标记说明:

last: <font color="red"># 本条规则匹配完成后,继续向下匹配新的 location URI 规则 </font>

break: <font color="red"># 本条规则匹配完成即终止,不再匹配后面的任何规则 </font>

redirect: <font color="red"># 返回 302 临时重定向,浏览器地址会显示跳转后的 URL 地址 </font>

permanment: <font color="red"># 返回 301 永久重定向,浏览器地址栏会显示跳转后的 URL 地址 </font>

URLRewrite 的优缺点

优点:掩藏真实的 url 以及 url 中可能暴漏的参数,以及隐藏 web 使用的编程语言,提高安全性便于搜索引擎收录

缺点:降低效率,影响性能,如果项目是内网使用,比如公司内部软件,则没有必要配置

# 负载均衡 + URLRewrite

image_2023-01-31-20-25-32

开启 101 的防火墙

systemctl start firewalld
  • 重载规则
firewalld-cmd --reload
  • 查看已配置规则
firewalld-cmd --list-all
  • 设置规则需要注意的是:ip 为目标开放主机,端口号为本机要开放的端口号

  • 添加指定端口和 ip 访问(添加之后记得重新启动防火墙)

firewalld-cmd --permanent --add-rich-rule="rule family="ipv4" source address="192.168.244.128" port protocol="tcp" port="8088" accept"
  • ip: 为 0 号 Linux 的 ip

  • port: 为 1 号 Linux 要开放的 Nginx 端口不需要开放 Tomcat 的端口号,也能访问到

  • 移除规则

firewalld-cmd --permanent --remove-rich-rule="rule family="ipv4" source address="192.168.8.102" port protocol="tcp" port="8080" accept"
  • 重启防火墙
firewalld-cmd --reload

测试:

  • 将 1 号 Linux 开启防火墙,然后通过 0 号 Linux 反向代理访问一下页面

image_2023-01-31-16-00-49

访问不到 Error 了

执行命令让 1 号 Linux 不让内网访问到但是可以让 0 号 Linux 的 Nginx 访问到

当我们配置如下配置后:

  • 0 号 Linux 配置如下:
server {
        listen       8089;
        server_name localhost;
        location / {
	    #httpds随便起的别名,但是要与upstream对应得上,upstream和server是同一级别的
     	    proxy_pass http://192.168.244.139:8088;
	    #root 只能查找本机中根目录的项目
            #root   http://www.qq.com;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
	
	#正则中不区分大小写,使用格式:(x|x|x|x)
        location ~*/(js|css|img|fonts) {
	    root html;
            index  index.html index.htm;
        }

    }
  • 1 号 Linux 配置如下:
 server {
        listen       8088;
        server_name  localhost;

        location / {
	    proxy_pass http://192.168.244.139:8080/ngintestday28/web/;
	    #root /www;
            index  index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

    }

1 号 Linux 对 0 号 Linux 开放端口的设置信息如下:

rule family="ipv4" source address="192.168.244.128" port port="8088" protocol="tcp" accept

命令为如下:

sudo firewall-cmd --permanent --add-rich-rule="rule family="ipv4" source address="目标机IP(访问机)" port protocol="协议" port="本机Nginx端口" accept"

# URLRewirte 应用场景
# 配置方式

# 动静分离原理

/css 的优先级比 / 高

location / {#优先级比/css低
        #httpds随便起的别名,但是要与upstream对应得上,upstream和server是同一级别的
        proxy_pass http://192.168.244.139:8088;
        #root 只能查找本机中根目录的项目
    #root   http://www.qq.com;
    index  index.html index.htm;                                                                                                                  
}
error_page   500 502 503 504  /50x.html;
location = /50x.html {
    root   html;
}

#uri地址
location /css {#优先级比/高
    #root 只能查找本机中根目录的项目
    #不需要加额外的目录,在访问时会指向根路径然后顺便加上uri的地址同时拼接
    root   html;
    index  index.html index.htm;
}