013.Nginx动静分离
Nginx动静分离
动静分离是指通过各种中间件技术,将用户的动态请求与静态请求分离,静态请求的资源能够直接通过中间件返回到客户端,以减少不必要的资源开销和请求延时;即便动态服务不可用,静态资源仍不会收到影响
单节点动静分离

此前的nginx配置没有做到真正的动静分离,\.php$匹配最终都交给了PHP程序进行处理,由PHP返回资源到用户,即便是由/匹配到的index.php也仍由PHP程序处理,再返回图片到用户。此示意图中,负载均衡节点不是必须的,只不过通过负载均衡更便于查看测试结果
| 节点 | 服务 |
|---|---|
| lb01 | Nginx Proxy |
| web01 | Nginx Static |
| web02 | Tomcat Server |
- 在web01上配置静态资源
[root@web01 ~]# vim /usr/local/nginx/conf.d/static.example.com.conf
server {
listen 80;
server_name static.example.com;
root /usr/local/nginx/html/;
index static.html;
location ~* .*\.(png|jpg|gif)$ {
root /usr/local/nginx/html/images/; # location配置优先生效
}
}
[root@web01 ~]# mkdir /usr/local/nginx/html/images/
[root@web01 ~]# wget -O /usr/local/nginx/html/images/nginx.png http://nginx.org/nginx.png
[root@web01 ~]# systemctl restart nginx
- 在web02节点上配置动态资源
[root@web02 ~]# yum install -y tomcat
[root@web02 ~]# mkdir /usr/share/tomcat/webapps/ROOT/
[root@web02 ~]# vim /usr/share/tomcat/webapps/ROOT/java_test.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<HTML>
<HEAD>
<TITLE>JSP Test Page</TITLE>
</HEAD>
<BODY>
<%
Random rand = new Random();
out.println("<h1>Random number:</h1>");
out.println(rand.nextInt(99)+100);
%>
</BODY>
</HTML>
[root@web02 ~]# systemctl restart tomcat
- 在lb01节点配置代理
[root@lb01 ~]# vim /etc/nginx/conf.d/lb01_static.conf
upstream static {
server 172.16.1.7:80;
}
upstream java {
server 172.16.1.8:8080;
}
server {
listen 80;
server_name static.example.com;
root /usr/share/nginx/html/;
index index.html; # 为动态、静态内容准备一个主页
location ~* .*\.(png|jpg|gif)$ {
proxy_pass http://static;
proxy_set_header Host $http_host;
}
location ~ \.jsp {
proxy_pass http://java;
}
}
- 在lb01节点上准备一个主页
[root@lb01 ~]# mv /usr/share/nginx/html/index.html /usr/share/nginx/html/index.html.bak
[root@lb01 ~]# vim /usr/share/nginx/html/index.html
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>测试ajax和跨域访问</title>
<script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
</head>
<script type="text/javascript">
$(document).ready(function(){
$.ajax({
type: "GET",
url: "http://static.example.com/java_test.jsp",
success: function(data) {
$("#get_data").html(data)
},
error: function(){
alert("fail!!,请刷新再试!");
}
});
});
</script>
<body>
<h1>测试动静分离</h1>
<img src="http://static.example.com/nginx.png">
<div id="get_data"></div>
</body>
</html>
Nginx资源分离场景
Nginx通过负载均衡实现安卓、iphone、pc跳转到不同的web节点
| 节点 | 角色 | 端口 |
|---|---|---|
| lb01 | 负载均衡 | 80 |
| web01 | 提供Android页面 | 9090 |
| web01 | 提供iphone页面 | 9091 |
| web01 | 提供pc页面 | 9092 |
- web01节点准备配置文件
[root@web01 ~]# vim /usr/local/nginx/conf.d/phone.example.com
server {
listen 9090;
root /usr/local/nginx/html/android/;
index android.html;
}
server {
listen 9091;
root /usr/local/nginx/html/iphone/;
index iphone.html;
}
server {
listen 9092;
root /usr/local/nginx/html/pc/;
index pc.html;
}
- web01节点准备站点环境
[root@web01 ~]# mkdir /usr/local/nginx/html/{android,iphone,pc}
[root@web01 ~]# echo "android" > /usr/local/nginx/html/android/android.html
[root@web01 ~]# echo "iphone" > /usr/local/nginx/html/iphone/iphone.html
[root@web01 ~]# echo "pc" > /usr/local/nginx/html/pc/pc.html
- lb01节点负载
[root@lb01 ~]# vim /etc/nginx/conf.d/proxy.phone.conf
upstream Android {
server 172.16.1.7:9090;
}
upstream iphone {
server 172.16.1.7:9091;
}
upstream pc {
server 172.16.1.7:9092;
}
server {
listen 80;
server_name agent.example.com;
location / {
if ($http_user_agent ~* "Android") {
proxy_pass http://Android;
}
if ($http_user_agent ~* "iphone") {
proxy_pass http://iphone;
}
if ($http_user_agent ~* "MSIE") { # 拒绝向来源客户端是IE浏览器的访问
return 403;
}
proxy_pass http://pc; # 默认匹配pc页面
}
}
[root@lb01 ~]# systemctl restart nginx
扩展:匹配手机端跳转
server {
listen 80;
server_name agent.example.com;
location / {
if ($http_user_agent ~* "Android|iphone") {
rewirte ^/$ https://www.baidu.com redirect;
}
proxy_pass http://pc; # 默认匹配pc页面
}
}
此配置中所有移动端的的访问请求都会被跳转到百度首页,pc端的访问仍正常返回
扩展:location匹配
location ~* ^\/sp/(.*) {
proxy_pass http://health/$1;
}
$1代表(.*),这意味着无论用户访问/sp/目录下的任何路径,都会转发到health资源池下的相对路径
Rewrite
Rewrite主要实现url地址重写、重定向,将转发到web节点的url重定向到其他url
- Rewrite使用场景
- 地址跳转:用户访问github.com这个url时,将其重定向到新的域名gitee.com
- 协议跳转:用户通过http协议请求网站时,将其重新跳转到https协议
- 伪静态:将动态页面显示为静态页面方式的一种技术,便于搜索引擎的录入,同时减少动态URL地址对外暴露过多的参数,提升安全性
- 搜索引擎:SEO优化依赖于url路径,好记的url便于支持搜索引擎录入
Rewrite配置
- 指令
Syntax: rewrite regex replacement [flag];
Default: --
Context: server, location, if
# rewrite ^(.*)$ /page/maintain.html break; # 切换维护页面场景
- Rewrite标记Flag
rewrite指令根据表达式重定向URI,或修改字符串。每行rewrite指令最后跟一个flag标记,支持的flag标记有如下表
| flag | 描述 |
|---|---|
| last | 本条规则匹配完成后,停止匹配,不再匹配后面的规则 |
| break | 本条规则匹配完成后,停止匹配,不再匹配后面的规则 |
| redirect | 返回302临时重定向,地址栏会显示跳转后的地址 |
| permanent | 返回301永久重定向,地址栏会显示跳转后的地址 |
last和break所指的“停止匹配”,是指在当前location的rewrite下面的其他规则,不再匹配。但是站点仍会继续匹配其他的location
last与break的区别对比示例
# 新建nginx配置文件
[root@web03 ~]# vim /usr/local/nginx/conf.d/rewrite.example.com.conf
server {
listen 80;
server_name rewrite.example.com;
root /usr/local/nginx/html/;
location ~ ^/break {
rewrite ^/break /test/ break;
}
location ~ ^/last {
rewrite ^/last /test/ last;
}
location /test/ {
default_type application/json; # 默认类型会直接下载,为了查看last的效果修改默认类型
return 200 'ok';
}
}
以上述配置为例,假设用户访问的是rewrite.example.com/break,此时匹配break,nginx会到/usr/local/nginx/html/test目录下去找默认的index.html文件,如果这个文件不存在,nginx返回404;如果这个文件存在,nginx会将break匹配规则中的路径test/目录追加到root路径下,再次访问站点rewrite.example.com/test/,这个请求被location /test/匹配,所以返回“ok”
假设用户访问的是rewrite.example.com/last,此时匹配last,nginx会直接将last匹配规则中的路径test/目录追加到root路径下,再次访问站点rewrite.example.com/test/;last不会去检查匹配规则的路径下是否存在默认文件,而是直接将请求转交给站点
从上述配置的检查结果能够非常明显的看出break和last的区别,在test/目录下不存在任何文件的情况下,break返回404、last返回“ok”,在test/目录下存在默认文件的情况下,break和last都返回“ok”,如果想直接显示test/index.html文件的内容,将location /test/区块注释即可,location /test/区块是为了便于理解才写的
redirect与permanent区别对比示例
[root@web03 ~]# vim /usr/local/nginx/conf.d/rewrite.example.com.conf
server {
listen 80;
server_name rewrite.example.com;
root /usr/local/nginx/html/;
location ~ ^/redirect {
rewrite ^(.*)$ https://www.baidu.com redirect;
rewrite ^(.*)$ https://www.baidu.com permanent;
}
}
redirect每次请求都会询问服务器,当服务器不可用时跳转失败;permanent第一次请求会询问服务器,之后浏览器会记住跳转地址,后续的跳转则不再询问服务器,直接通过浏览器缓存地址跳转,即便服务器不可用也不会影响用户使用
跳转示例
- 示例1:http://web03.example.com/abc/1.html -> http://web03.example.com/ccc/bbb/2.html
# 1.新建web03虚拟机,修改主机名/IP
# 2.新建nginx配置文件
[root@web03 ~]# vim /usr/local/nginx/conf.d/rewrite.example.com.conf
server {
listen 80;
server_name rewrite.example.com;
location / {
root /usr/local/nginx/html/;
index index.html;
}
location /abc {
rewrite (.*) /ccc/bbb/2.html redirect;
}
}
# 3.准备站点环境
[root@web03 ~]# mkdir -p /usr/local/nginx/html/ccc/bbb/
[root@web03 ~]# echo "ccc_bbb" > /usr/local/nginx/html/ccc/bbb/2.html
[root@web03 ~]# systemctl restart nginx
- 实例2:用户访问
/2023/ccc/bbb/2.html跳转到/2020/ccc/bbb/2.html
# 1.准备访问路径
[root@web03 ~]# mkdir /usr/local/nginx/html/2020/ccc/bbb/ -p
[root@web03 ~]# echo "2020_ccc_bbb" > /usr/local/nginx/html/2020/ccc/bbb/2.html
# 2.nginx配置
location ~ /2023 {
rewrite ^/2023/(.*)$ /2020/$1 redirect;
}
- 示例3:用户访问
/test/目录下任何内容都跳转到http://www.baidu.com
location /test/ {
rewrite ^(.*)$ http://www.baidu.com redirect;
}
- 示例4:用户访问
course-11-22-33.html跳转到/course/11/22/33/course_33.html
# 1.站点目录
[root@web03 ~]# mkdir /usr/local/nginx/html/course/11/22/33/ -p
[root@web03 ~]# mkdir /usr/local/nginx/html/course/44/55/66/ -p
[root@web03 ~]# echo "123" > /usr/local/nginx/html/course/11/22/33/course_33.html
[root@web03 ~]# echo "456" > /usr/local/nginx/html/course/44/55/66/course_66.html
# 2.nginx配置
location ~ ^/course {
rewrite (.*)-(.*)-(.*)-(.*)\.(.*) /$1/$2/$3/$4/$1_$4.$5 break;
}
[root@web03 ~]# systemctl restart nginx
# 3.打开rewrite调试日志
[root@web03 ~]# vim /usr/local/nginx/nginx.conf
error_log /logs/error.log notice;
http{
rewirte_log on;
...
}
- 示例5:http请求跳转到https
server {
listen 80;
server_name rewrite.example.com;
rewrite ^(.*) https://$server_name$1 redirect;
#return 302 https://$server_name$request_uri; # 与上例达到同样效果
}
server {
listen 443 ssl;
server_name rewrite.example.com;
}
此示例中,$1和$request_uri都是将用户请求的具体资源路径追加到https站点主目录下,如果不加这两个参数,每一次http都会重新跳转到站点的https首页;URL是指的站点地址+用户请求的资源路径、URI单独指用户请求的资源路径;rewrite常用于URI地址替换(示例4)、return常用语http转https(示例5),return不能使用正则表达式,只能返回响应码和跳转地址,使用return返回响应码时需要注意301和302的使用,301代表永久跳转permanent
示例5在虚拟机没有ssl证书的情况下,nginx会提示配置有误,换成百度的https站点测试即可

浙公网安备 33010602011771号