013.Nginx动静分离

Nginx动静分离

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

单节点动静分离

Nginx单节点动静分离

此前的nginx配置没有做到真正的动静分离,\.php$匹配最终都交给了PHP程序进行处理,由PHP返回资源到用户,即便是由/匹配到的index.php也仍由PHP程序处理,再返回图片到用户。此示意图中,负载均衡节点不是必须的,只不过通过负载均衡更便于查看测试结果

节点 服务
lb01 Nginx Proxy
web01 Nginx Static
web02 Tomcat Server
  1. 在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
  1. 在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
  1. 在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;
	}
}
  1. 在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
  1. 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;
}
  1. 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
  1. 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使用场景
  1. 地址跳转:用户访问github.com这个url时,将其重定向到新的域名gitee.com
  2. 协议跳转:用户通过http协议请求网站时,将其重新跳转到https协议
  3. 伪静态:将动态页面显示为静态页面方式的一种技术,便于搜索引擎的录入,同时减少动态URL地址对外暴露过多的参数,提升安全性
  4. 搜索引擎:SEO优化依赖于url路径,好记的url便于支持搜索引擎录入

Rewrite配置

  1. 指令
Syntax: rewrite regex replacement [flag];
Default: --
Context: server, location, if

# rewrite ^(.*)$ /page/maintain.html break;		# 切换维护页面场景
  1. 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. 示例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
  1. 实例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;
}
  1. 示例3:用户访问/test/目录下任何内容都跳转到http://www.baidu.com
location /test/ {
	rewrite ^(.*)$ http://www.baidu.com redirect;
}
  1. 示例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;
	...
}
  1. 示例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站点测试即可

posted @ 2023-06-19 09:22  hebo  阅读(37)  评论(0)    收藏  举报