- Nginx优化及防盗链
- 2、工作进程数优化
- 3、Nginx事件处理模型
- 4、开启高效传输模式
- 5、连接超时时间
- 6、fastcgi调优
- 7、gzip调优
- 8、配置网页缓存时间
- 9、防盗链
- 10、内核参数优化
- fs.file-max = 999999:
- net.ipv4.tcp_max_tw_buckets = 6000
- net.ipv4.ip_local_port_range = 1024 65000
- net.ipv4.tcp_tw_recycle = 1
- net.ipv4.tcp_tw_reuse = 1
- net.ipv4.tcp_keepalive_time = 30
- net.ipv4.tcp_syncookies = 1
- net.core.somaxconn = 40960
- net.core.netdev_max_backlog = 262144
- net.ipv4.tcp_max_syn_backlog = 262144
- net.ipv4.tcp_rmem = 10240 87380 12582912
- net.ipv4.tcp_wmem = 10240 87380 12582912
- net.core.rmem_default = 6291456
- net.core.wmem_default = 6291456
- net.core.rmem_max = 12582912
- net.core.wmem_max = 12582912
- 内核优化案例
- 实验优化案例
- 验证、压力测试
- Nginx Rewrite
Nginx优化及防盗链
在企业信息化应用环境中,服务器的安全性和响应速度需要根据实际情况进行相应参数配置,以达到最优的用户体验。默认的Nginx安装参数只能提供最基本的服务,需要调整如网页缓存时间、连接超时、网页压缩等相应参数,发挥出服务器的最大作用。
1、隐藏版本等信息
在生产环境中,需要隐藏Nginx的版本号,以避免泄漏Nginx的版本,使攻击者不能针对特定版本进行攻击。
优化前访问:
HTTP/1.1 200 OKServer: nginx/1.16.0 #版本信息Date: Thu, 04 Jul 2019 15:06:57 GMTContent-Type: text/html; charset=utf-8Content-Length: 626Last-Modified: Mon, 01 Jul 2019 09:26:46 GMTConnection: keep-aliveETag: "5d19d1d6-272"Accept-Ranges: bytes
优化方式:
- 修改主配置文件:
将Nginx的配置文件中的server_tokens选项值设置为off,如没有该配置项,加上即可。
http {include mime.types;default_type application/octet-stream;server_tokens off;.................. #省略很多内容}
使用了php处理动态网页,如果php配置文件中配置了fastcgi_param SERVER_SOFTWARE选项,则编辑php-fpm配置文件,将 fastcgi_param SERVER
_SOFTWARE对应的值修改为fastcgi_param SERVER _SOFTWARE nginx。
重启服务后,再次查看:
[root@localhost ~]# curl -I http://127.0.0.1HTTP/1.1 200 OKServer: nginx............ #省略很多
- 编译安装前修改源码
编译前的优化主要是用来修改程序名等等,目的更改源码隐藏软件名称和版本号。
- 进入解压后的源码目录,进行修改
修改前
[root@localhost nginx-1.16.0]# vim src/core/nginx.h#define NGINX_VERSION "1.16.0" #定义的版本号#define NGINX_VER "nginx/" NGINX_VERSION #定义的软件名称
修改后
[root@localhost nginx-1.16.0]# vim src/core/nginx.h#define NGINX_VERSION "7.0"#define NGINX_VER "IIS/" NGINX_VERSION
- 修改HTTP头信息中的connection字段,防止回显具体版本号
拓展:通用http头,通用头包含请求和响应消息都支持的头,通用头包含Cache-Control、Connection、 Date、 Pragma、 Transfer-Encoding、Upgrade、 Via。对通用头的扩展要求通讯双方都支持此扩展,如果存在不支持的通用头,一般将会作为实体头处理。那么也就是说有部分设备,或者是软件,能获取到connection部分不能,要隐藏就要彻底!
修改前:
[root@localhost nginx-1.16.0]# vim src/core/nginx.hstatic u_char ngx_http_error_tail[] ="<hr><center>nginx</center>" CRLF"</body>" CRLF"</html>" CRLF;
修改后:
static u_char ngx_http_error_tail[] ="<hr><center>IIS</center>" CRLF"</body>" CRLF"</html>" CRLF;
修改完毕后进行编译安装,安装完成后,查看测试:
[root@localhost nginx-1.16.0]# curl -I http://127.0.0.1HTTP/1.1 200 OKServer: IIS/7.0.............. #省略很多内容
2、工作进程数优化
Nginx默认只开启一个worker进程,一般都设置为CPU个数,查看CPU个数使用如下命令:
[root@localhost nginx-1.16.0]# grep -c 'processor' /proc/cpuinfo4
所以应该配置成:
worker_processes 4;worker_cpu_affinity 0001 0010 0100 1000; #将每个工作进程绑定到单独的CPUworker_rlimit_nofile 65535; #工作进程打开的最大文件数
也可以这样调整(1.9.0版本后)
worker_processes auto;worker_cpu_affinity auto;#1.9.10版本后允许将工作进程自动绑定到可用的CPU
打开的最大文件数还要和系统的一致,使用ulimit -n查看,如果不一致,需要调整
[root@localhost nginx-1.16.0]# vim /etc/security/limits.conf* soft nofile 65535* hard nofile 65535* soft noproc 65535* hard noproc 65535
3、Nginx事件处理模型
events {use epoll;worker_connections 8192;accept_mutex on;multi_accept on;}
nginx采用epoll事件模型,处理效率高。
work_connections是单个worker进程允许客户端最大连接数,这个数值一般根据服务器性能和内存来制定,实际最大值就是worker进程数乘以work_connections
accept_mutex如果启用on,工作进程将轮流接受新的连接。否则,将通知所有工作进程有关新连接的信息,但只有一个进程可以获得连接。如果新连接的数量较低,则某些工作进程可能会浪费系统资源。如果是并发连接数很大的情况,应该调整为off。新版本默认是off,在版本1.11.3之前,默认值为on。
multi_accept指令使得NGINXworker能够在获得新连接的通知时尽可能多的接受连接。 此指令的作用是立即接受所有连接放到监听队列中。如果指令被禁用,worker进程将逐个接受连接。默认是off。
4、开启高效传输模式
http {include mime.types;default_type application/octet-stream;sendfile on;tcp_nopush on;
include mime.types; //媒体类型,include只是一个在当前文件中包含另一个文件内容的指令
default_type application/octet-stream; //默认媒体类型足够
sendfile on; //开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。当Nginx是一个静态文件服务器的时候,开启sendfile配置项能大大提高Nginx的性能.
tcp_nopush on; 必须在sendfile开启模式才有效,防止网路阻塞,积极的减少网络报文段的数量(告诉nginx在一个数据包里发送所有头文件,而不一个接一个的发送。同tcp_nodelay选项互斥)
5、连接超时时间
主要目的是保护服务器资源,CPU,内存,控制连接数,因为建立连接也是需要消耗资源的
keepalive_timeout 60;tcp_nodelay on;client_header_buffer_size 4k;open_file_cache max=102400 inactive=20s;open_file_cache_valid 30s;open_file_cache_min_uses 1;client_header_timeout 15;client_body_timeout 15;reset_timedout_connection on;send_timeout 15;server_tokens off;client_max_body_size 10m;
keepalived_timeout 客户端连接保持会话超时时间,超过这个时间,服务器断开这个链接
tcp_nodelay off,会增加通信的延时,但是会提高带宽利用率。在高延时、数据量大的通信场景中应该会有不错的效果;tcp_nodelay on,会增加小包的数量,但是可以提高响应速度。在及时性高的通信场景中应该会有不错的效果;
client_header_buffer_size 4k;
客户端请求头部的缓冲区大小,这个可以根据你的系统分页大小来设置,一般一个请求头的大小不会超过1k,不过由于一般系统分页都要大于1k,所以这里设置为分页大小。分页大小可以用命令getconf PAGESIZE取得。
open_file_cache max=102400 inactive=20s;
这个将为打开文件指定缓存,默认是没有启用的,max指定缓存数量,建议和打开文件数一致,inactive是指经过多长时间文件没被请求后删除缓存。
open_file_cache_valid 30s;这个是指多长时间检查一次缓存的有效信息。
open_file_cache_min_uses 1;open_file_cache 指令中的 inactive 参数时间内文件的最少使用次数,如果超过这个数字,文件描述符一直是在缓存中打开的,如上例,如果有一个文件在inactive时间内一次没被使用,它将被移除
client_header_timeout设置请求头的超时时间。我们也可以把这个设置低些,如果超过这个时间没有发送任何数据,nginx将返回request time out的错误
client_body_timeout设置请求体的超时时间。我们也可以把这个设置低些,超过这个时间没有发送任何数据,和上面一样的错误提示
reset_timeout_connection 告诉nginx关闭不响应的客户端连接。这将会释放那个客户端所占有的内存空间。
send_timeout 响应客户端超时时间,这个超时时间仅限于两个活动之间的时间,如果超过这个时间,客户端没有任何活动, nginx 关闭连接
client_max_body_size 上传文件大小限制。
6、fastcgi调优
fastcgi_connect_timeout 600;fastcgi_send_timeout 600;fastcgi_read_timeout 600;fastcgi_buffer_size 64k;fastcgi_buffers 4 64k;fastcgi_busy_buffers_size 128k;fastcgi_temp_file_write_size 128k;fastcgi_temp_path /usr/local/nginx1.10/nginx_tmp;fastcgi_intercept_errors on;fastcgi_cache_path /usr/local/nginx1.10/fastcgi_cache levels=1:2 keys_zone=cache_fastcgi:128minactive=1d max_size=10g;
fastcgi_connect_timeout 600; #指定连接到后端 FastCGI 的超时时间。
fastcgi_send_timeout 600; #向 FastCGI 传送请求的超时时间。
fastcgi_read_timeout 600; #指定接收 FastCGI 应答的超时时间。
fastcgi_buffer_size 64k; #指定读取FastCGI应答第一部分需要用多大的缓冲区, 默认的缓冲区大小为 一个内存页大小(4K或者8K),可以将这个值设置更小。
fastcgi_buffers 4 64k; #指定本地需要用多少和多大的缓冲区来缓冲 FastCGI 的应答请求,如果一个php脚本所产生的页面大小为256KB,那么会分配 4 个 64KB 的缓冲区来缓存,如果页面大小大于 256KB,那么大于 256KB 的部分会缓存到fastcgi_temp_path指定的路径中,但是这并不是好方法,因为内存中的数据处理速度要快于磁盘。一般这个值应该为站点中 php
脚本所产生的页面大小的中间值,如果站点大部分脚本所产生的页面大小为 256KB,那么可以把这个值设置为“8 32K”、 “4 64k”等。
fastcgi_busy_buffers_size 128k; #建议设置为fastcgi_buffers的两倍,繁忙时候的 buffer
fastcgi_temp_file_write_size 128k; #在写入 fastcgi_temp_path 时将用多大的数据块,默认值是fastcgi_buffers的两倍,该数值设置小时若负载上来时可能报 502 Bad Gateway
fastcgi_temp_path #缓存临时目录
fastcgi_intercept_errors on;# 这个指令指定是否传递 4xx 和 5xx 错误信息到客户端,或者允许nginx 使用 error_page 处理错误信息。
注: 静态文件不存在会返回 404 页面,但是 php 页面则返回空白页!
fastcgi_cache_path /usr/local/nginx1.10/fastcgi_cache levels=1:2 keys_zone=cache_fastcgi:128m inactive=1d max_size=10g; # fastcgi_cache 缓存目录,可以设置目录层级,比如 1:2 会生成
16*256 个子目录, cache_fastcgi 是这个缓存空间的名字, cache 是用多少内存(这样热门的内容 nginx 直接放内存,提高访问速度), inactive 表示默认失效时间,如果缓存数据在失效时间内没有被访问,将被删除, max_size 表示最多用多少硬盘空间。
fastcgi_cache cache_fastcgi; #表示开启 FastCGI 缓存并为其指定一个名称。开启缓存非常有用,可以有效降低 CPU的负载,并且防止 502 的错误放生。cache_fastcgi为proxy_cache_path
指令创建的缓存区名称
fastcgi_cache_valid 200 302 1h;#用来指定应答代码的缓存时间,实例中的值表示将200和302应答缓存一小时,要和 fastcgi_cache 配合使用
fastcgi_cache_valid 301 1d; #将301应答缓存一天
fastcgi_cache_valid any 1m; #将其他应答缓存为1分钟
fastcgi_cache_min_uses 1; #该指令用于设置经过多少次请求的相同URL将被缓存。
fastcgicache_key http://host_hostrequest_uri; #该指令用来设置web缓存的Key值,nginx根据Key值md5哈希存储,一般根据host( 域名 )、host(域名)、request_uri(请求的路径 ) 等变量组合成proxy_cache_key
总结:
nginx的缓存功能有:proxy_cache和fastcgi_cache
- proxy_cache 的作用是缓存后端服务器的内容,可能是任何内容,包括静态的和动态。
- fastcgi_cache 的作用是缓存fastcgi生成的内容,很多情况是php生成的动态的内容。
- proxy_cache 缓存减少了nginx与后端通信的次数,节省了传输时间和后端宽带。
- fastcgi_cache 缓存减少了nginx与php的通信的次数,更减轻了php和数据库(mysql)的压力。
7、gzip调优
使用gzip压缩功能,可节约带宽,加快传输速度,有更好的体验,也为我们节约成本,所以说这是一个重点。Nginx启用压缩功能需要你来ngx_http_gzip_module模块,apache使用的是mod_deflate。一般我们需要压缩的内容有:文本,js,html,css,对于图片,视频,flash什么的不压缩,同时也要注意,使用gzip的功能是需要消耗CPU的。
gzip on;gzip_min_length 2k;gzip_buffers 4 32k;gzip_http_version 1.1;gzip_comp_level 6;gzip_types text/plain text/css text/javascript application/json application/javascriptapplication/x-javascript application/xml;gzip_vary on;gzip_proxied any;
gzip on; #开启压缩功能
gzip_min_length 1k; #设置允许压缩的页面最小字节数,页面字节数从 header 头的Content-Length中获取,默认值是20字节,建议设置成大于1K,如果小于1K可能会越压越大。
gzip_buffers 4 32k; #压缩缓冲区大小,表示申请4个单位为32K的内存作为压缩结果流缓存,
默认值是申请与原始数据大小相同的内存空间来存储gzip压缩结果。
gzip_http_version 1.1; #压缩版本,用于设置识别HTTP协议版本,默认是 1.1,目前大部分浏览器已经支持GZIP解压,使用默认即可
gzip_comp_level 6; #压缩比例,用来指定GZIP压缩比,1压缩比最小,处理速度最快,9压缩比最大,传输速度快,但是处理慢,也比较消耗 CPU 资源。默认是1
gzip_types text/css text/xml application/javascript; #用来指定压缩的类型, ‘text/html’类型总是会被压缩。默认值: gzip_types text/html (默认不对 js/css 文件进行压缩)
gzip_vary on; #开启和关闭插入“Vary: Accept-Encoding”响应头区域
gzip_proxied any; #Nginx作为反向代理的时候启用,根据后端服务器的相应头区域是否有“Via”
区域来开启或者是关闭压缩。any就是所有的代理请求都压缩。
8、配置网页缓存时间
当Nginx将网页数据返回给客户端后,可设置缓存的时间,以方便在日后进行相同内容的请求时直接返回,以避免重复请求,加快了访问速度,一般针对静态资源进行设置,对动态网页不用设置缓存时间。下面对图片做缓存配置:
location ~ \.(gif|jpg|jepg|png|bmp|ico)$ { #加入新的locationroot html;expires 1d; #指定缓存时间}
设置缓存一天的时间,一天之内浏览器访问这个页面,都是用缓存中的数据,而不需要向Nginx服务器重新发出请求,减少了服务器的使用带宽。
总结:
expire功能优点:
- expires可以降低网站购买的带宽,节约成本
- 同时提升用户访问体验
- 减轻服务的压力,节约服务器成本,是web服务非常重要的功能。
expire功能缺点:
- 被缓存的页面或数据更新了,用户看到的可能还是旧的内容,反而影响用户体验。
- 解决办法:
- 第一个缩短缓存时间,例如:1天,但不彻底,除非更新频率大于1天;
- 第二个对缓存的对象改名。
- 网站不希望被缓存的内容:
- 网站流量统计工具
- 更新频繁的文件(google的logo)
9、防盗链
在企业网站服务中,一般都要配置防盗链功能,以避免网站内容被非法盗用,造成经济损失,也避免了不必要的带宽浪费。Nginx的防盗链功能也非常强大,在默认情况下,只需要进行很简单的配置,即可实现防盗链处理。
location ~* \.(jpg|gif|swf)$ {valid_referers none blocked *.bt.com bt.com;if ($invalid_referer) {rewrite ^/ http://www.bt.com/error.png;}}
Nginx的防盗链原理是加入location项,用正则表达式过滤图片类型文件,对于信任的网址可以正常使用,不信任的网址返回相应的错误图片。
10、内核参数优化
fs.file-max = 999999:
这个参数表示进程(比如一个 worker 进程)可以同时打开的最大句柄
数,这个参数直线限制最大并发连接数,需根据实际情况配置。
net.ipv4.tcp_max_tw_buckets = 6000
这个参数表示操作系统允许TIME_WAIT套接字数量的最大值,如果超过这个数字, TIME_WAIT 套接字将立刻被清除并打印警告信息。该参数默认为 180000,过多的 TIME_WAIT 套接字会使 Web 服务器变慢。
注: 主动关闭连接的服务端会产生 TIME_WAIT 状态的连接
net.ipv4.ip_local_port_range = 1024 65000
允许系统打开的端口范围
net.ipv4.tcp_tw_recycle = 1
启用timewait快速回收
net.ipv4.tcp_tw_reuse = 1
开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接。这对于服务器来说很有意义,因为服务器上总会有大量TIME-WAIT状态的连接。
net.ipv4.tcp_keepalive_time = 30
这个参数表示当 keepalive启用时,TCP发送keepalive消息的频度。默认是2小时,若将其设置的小一些,可以更快地清理无效的连接。
net.ipv4.tcp_syncookies = 1
开启SYN Cookies当出现SYN等待队列溢出时,启用cookies来处理,该参数与性能无关,用于解决TCP的SYN攻击。
net.core.somaxconn = 40960
web 应用中 listen 函数的 backlog 默认会给我们内核参数的
net.core.somaxconn 限制到 128,而 nginx 定义的 NGX_LISTEN_BACKLOG 默认为 511,所以有必要调整这个值。
注: 对于一个 TCP连接,Server与Client需要通过三次握手来建立网络连接.当三次握手成功后,我们可以看到端口的状态由LISTEN转变为ESTABLISHED,接着这条链路上就可以开始传送数据了.每一个处于监听(Listen)状态的端口,都有自己的监听队列.监听队列的长度于此somaxconn参数和使用该端口的程序中 listen()函数有关
somaxconn 参数:定义了系统中每一个端口最大的监听队列的长度,这是个全局的参数,默认值为128,对于一个经常处理新连接的高负载web服务环境来说,默认的 128 太小了。大多数环境这个值建议增加到1024或者更多。大的侦听队列对防止拒绝服务 DoS 攻击也会有所帮助。
net.core.netdev_max_backlog = 262144
每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。
net.ipv4.tcp_max_syn_backlog = 262144
这个参数标示 TCP 三次握手建立阶段接受 SYN请求队列的最大长度,默认为 1024,将其设置得大一些可以使出现Nginx繁忙来不及accept新连接的情况时, Linux 不至于丢失客户端发起的连接请求。
net.ipv4.tcp_rmem = 10240 87380 12582912
这个参数定义了TCP接受缓存(用于TCP接受滑动窗口)的最小值、默认值、最大值。
net.ipv4.tcp_wmem = 10240 87380 12582912
这个参数定义了 TCP发送缓存(用于TCP发送滑动窗口)的最小值、默认值、最大值。
net.core.rmem_default = 6291456
这个参数表示内核套接字接受缓存区默认的大小。
net.core.wmem_default = 6291456
这个参数表示内核套接字发送缓存区默认的大小。
net.core.rmem_max = 12582912
这个参数表示内核套接字接受缓存区的最大大小。
net.core.wmem_max = 12582912
这个参数表示内核套接字发送缓存区的最大大小。
内核优化案例
fs.file-max = 999999net.ipv4.ip_forward = 0net.ipv4.conf.default.rp_filter = 1net.ipv4.conf.default.accept_source_route = 0kernel.sysrq = 0kernel.core_uses_pid = 1net.ipv4.tcp_syncookies = 1kernel.msgmnb = 65536kernel.msgmax = 65536kernel.shmmax = 68719476736kernel.shmall = 4294967296net.ipv4.tcp_max_tw_buckets = 6000net.ipv4.tcp_sack = 1net.ipv4.tcp_window_scaling = 1net.ipv4.tcp_rmem = 10240 87380 12582912net.ipv4.tcp_wmem = 10240 87380 12582912net.core.wmem_default = 8388608net.core.rmem_default = 8388608net.core.rmem_max = 16777216net.core.wmem_max = 16777216net.core.netdev_max_backlog = 262144net.core.somaxconn = 40960net.ipv4.tcp_max_orphans = 3276800net.ipv4.tcp_max_syn_backlog = 262144net.ipv4.tcp_timestamps = 0net.ipv4.tcp_synack_retries = 1net.ipv4.tcp_syn_retries = 1net.ipv4.tcp_tw_recycle = 1net.ipv4.tcp_tw_reuse = 1net.ipv4.tcp_mem = 94500000 915000000 927000000net.ipv4.tcp_fin_timeout = 1net.ipv4.tcp_keepalive_time = 30net.ipv4.ip_local_port_range = 1024 65000
执行sysctl -p使内核修改生效
实验优化案例
部署实验环境
1、部署LNMP环境(略)
2、一个完整的Nginx配置文件案例
user www www;worker_processes 4;worker_cpu_affinity 0001 0010 0100 1000;worker_rlimit_nofile 65535;error_log logs/error.log;#error_log logs/error.log notice;#error_log logs/error.log info;pid logs/nginx.pid;events {use epoll;worker_connections 8192;multi_accept on;}http {include mime.types;default_type application/octet-stream;log_format main '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';#access_log logs/access.log main;sendfile on;tcp_nopush on;keepalive_timeout 65;tcp_nodelay on;client_header_buffer_size 4k;open_file_cache max=102400 inactive=20s;open_file_cache_valid 30s;open_file_cache_min_uses 1;client_header_timeout 15;client_body_timeout 15;reset_timedout_connection on;send_timeout 15;server_tokens off;client_max_body_size 10m;fastcgi_connect_timeout 600;fastcgi_send_timeout 600;fastcgi_read_timeout 600;fastcgi_buffer_size 64k;fastcgi_buffers 4 64k;fastcgi_busy_buffers_size 128k;fastcgi_temp_file_write_size 128k;fastcgi_temp_path /usr/local/nginx1.10/nginx_tmp;fastcgi_intercept_errors on;fastcgi_cache_path /usr/local/nginx1.10/fastcgi_cache levels=1:2keys_zone=cache_fastcgi:128m inactive=1d max_size=10g;gzip on;gzip_min_length 2k;gzip_buffers 4 32k;gzip_http_version 1.1;gzip_comp_level 6;gzip_types text/plain text/css text/javascript application/json application/javascriptapplication/x-javascript application/xml;gzip_vary on;gzip_proxied any;server {listen 80;server_name www.shengzhe.com;#charset koi8-r;#access_log logs/host.access.log main;location ~* ^.+\.(jpg|gif|png|swf|flv|wma|wmv|asf|mp3|mmf|zip|rar)$ {valid_referers none blocked www.shengzhe.com shengzhe.com;if ($invalid_referer) {#return 302 http://www.shengzhe.com/img/nolink.jpg;return 404;break;}access_log off;}location / {root html;index index.php index.html index.htm;}location ~* \.(ico|jpe?g|gif|png|bmp|swf|flv)$ {expires 30d;#log_not_found off;access_log off;}location ~* \.(js|css)$ {expires 7d;log_not_found off;access_log off;}location = /(favicon.ico|roboots.txt) {access_log off;log_not_found off;}location /status {stub_status on;}location ~ .*\.(php|php5)?$ {root html;fastcgi_pass 127.0.0.1:9000;fastcgi_index index.php;include fastcgi.conf;fastcgi_cache cache_fastcgi;fastcgi_cache_valid 200 302 1h;fastcgi_cache_valid 301 1d;fastcgi_cache_valid any 1m;fastcgi_cache_min_uses 1;fastcgi_cache_use_stale error timeout invalid_header http_500;fastcgi_cache_key http://$host$request_uri;}#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;}}}
验证、压力测试
1、验证防盗链
使用Apache做为一个测试站点,域名为www.test.com,在测试页上做一个超链接,链接nginx站点的一张图片
[root@centos1 ~]# cat /var/www/html/index.html<h1> this is a tes </h1><img src="http://www.shengzhe.com/123.jpg">
Nginx站点的网页目录结如下:
[root@localhost nginx1.16]# tree -C /usr/local/nginx1.16/html//usr/local/nginx1.16/html/├── 123.jpg├── 50x.html├── img│ └── nolink.jpg├── index.html├── mysql_test.php└── test.html1 directory, 6 files[root@localhost nginx1.16]# vim test.html<h1>this is www.shengzhe.com test</h1><img src="http://www.shengzhe.com/123.jpg">
Nginx防盗链设置
location ~* \.(jpg|gif|swf|png)$ {root /usr/share/nginx/html;valid_referers server_names shengzhe.com shengzhe.com.* *.shengzhe.com;if ($invalid_referer) {#rewrite ^/ http://www.shengzhe.com/error.jpg;return 404;}}
在客户端浏览器中输入:www.test.com

而访问自己的站点是可以的

2、验证gzip功能
使用谷歌浏览器测试访问,如下图显示结果:(提示:在访问测试页之前按 F12 键)

用户访问test.php文件,在上图中content-encoding:gzip表明响应给用户的数据是压缩传输。
3、压力测试
网站性能压力测试是服务器网站性能调优过程中必不可缺少的一环。只有让服务器处在高压情况下,才能真正体现出软件、硬件等各种设置不当所暴露出的问题。
性能测试工具目前最常见的有以下几种:ab、http_load、webbench、siege。
ab是apache自带的压力测试工具。ab非常实用,它不仅可以对apache服务器进行网站访问压力测试,也可以对或其它类型的服务器进行压力测试。比如nginx、tomcat、IIS等。
需要安装才能使用:
[root@localhost ~]# yum install httpd-tools -y
最常用的参数:
-n 总的要执行多少个请求数-c 一次要发出的请求数(并发数)
执行以下测试命令
[root@localhost ~]# ab -c 500 -n 50000 http://192.168.154.140/index.htmlThis is ApacheBench, Version 2.3 <$Revision: 1430300 $>Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking 192.168.154.140 (be patient)Completed 5000 requestsCompleted 10000 requestsCompleted 15000 requestsCompleted 20000 requestsCompleted 25000 requestsCompleted 30000 requestsCompleted 35000 requestsCompleted 40000 requestsCompleted 45000 requestsCompleted 50000 requestsFinished 50000 requestsServer Software: nginxServer Hostname: 192.168.154.140Server Port: 80Document Path: /index.htmlDocument Length: 626 bytesConcurrency Level: 500Time taken for tests: 32.916 secondsComplete requests: 50000Failed requests: 12(Connect: 0, Receive: 0, Length: 6, Exceptions: 6)Write errors: 0Total transferred: 42600000 bytesHTML transferred: 31300000 bytesRequests per second: 1519.01 [#/sec] (mean)Time per request: 329.161 [ms] (mean)Time per request: 0.658 [ms] (mean, across all concurrent requests)Transfer rate: 1263.87 [Kbytes/sec] receivedConnection Times (ms)min mean[+/-sd] median maxConnect: 0 85 26.8 83 367Processing: 8 95 165.8 92 15002Waiting: 2 64 28.5 59 374Total: 82 181 165.5 172 15002Percentage of the requests served within a certain time (ms)50% 17266% 17975% 18480% 18790% 19895% 20998% 25099% 370100% 15002 (longest request)
ab性能指标
- 吞吐率
(Requests per second)
服务器并发处理能力的量化描述,单位是reqs/s,指的是在某个并发用户数下单位时间内处理的请求数。某个并发用户数下单位时间内能处理的最大请求数,称之为最大吞吐率。
记住:吞吐率是基于并发用户数的。这句话代表了两个含义:- 吞吐率和并发用户数相关
- 不同的并发用户数下,吞吐率一般是不同的
计算公式:总请求数/处理完成这些请求数所花费的时间,即
Request per second=Complete requests/Time taken for tests
必须要说明的是,这个数值表示当前机器的整体性能,值越大越好。
- 并发连接数(The number of concurrent connections)
并发连接数指的是某个时刻服务器所接受的请求数目,简单的讲,就是一个会话 - 并发用户数(Concurrency Level)
要注意区分这个概念和并发连接数之间的区别,一个用户可能同时会产生多个会话,也即连接数。在HTTP/1.1下,IE7支持两个并发连接,IE8支持6个并发连接,FireFox3支持4个并发连接,所以相应的,我们的并发用户数就得除以这个基数。 - 用户平均请求等待时间(Time per request)
计算公式:处理完成所有请求数所花费的时间/(总请求数/并发用户数),即:
Time per request=Time taken for tests/(Complete requests/Concurrency Level) - 服务器平均请求等待时间(Time per request:across all concurrent requests)
计算公式:处理完成所有请求数所花费的时间/总请求数,即:
Time taken for/testsComplete requests
可以看到,它是吞吐率的倒数。
同时,它也等于用户平均请求等待时间/并发用户数,即
Time per request/Concurrency Level
第二次压力测试,比较两次的差异
[root@localhost ~]# ab -c 1000 -n 100000 http://192.168.154.140/index.htmlThis is ApacheBench, Version 2.3 <$Revision: 1430300 $>Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking 192.168.154.140 (be patient)Completed 10000 requestsCompleted 20000 requestsCompleted 30000 requestsCompleted 40000 requestsCompleted 50000 requestsCompleted 60000 requestsCompleted 70000 requestsCompleted 80000 requestsCompleted 90000 requestsCompleted 100000 requestsFinished 100000 requestsServer Software: nginxServer Hostname: 192.168.154.140Server Port: 80Document Path: /index.htmlDocument Length: 626 bytesConcurrency Level: 1000Time taken for tests: 50.908 secondsComplete requests: 100000Failed requests: 39(Connect: 0, Receive: 0, Length: 20, Exceptions: 19)Write errors: 0Total transferred: 85200000 bytesHTML transferred: 62600000 bytesRequests per second: 1964.33 [#/sec] (mean)Time per request: 509.080 [ms] (mean)Time per request: 0.509 [ms] (mean, across all concurrent requests)Transfer rate: 1634.38 [Kbytes/sec] receivedConnection Times (ms)min mean[+/-sd] median maxConnect: 0 173 50.7 171 638Processing: 16 189 211.9 183 15010Waiting: 3 122 54.4 115 472Total: 191 361 207.8 349 15010Percentage of the requests served within a certain time (ms)50% 34966% 35975% 36680% 37190% 38595% 40098% 46199% 603100% 15010 (longest request)
4、opcache 提高PHP访问速度
Opcache 的前生是 Optimizer+,它是PHP的官方公司Zend开发的一款闭源但可以免费使用的 PHP优化加速组件。Optimizer+将PHP代码预编译生成的脚本文件 Opcode 缓存在共享内存中供以后反复使用,从而避免了从磁盘读取代码再次编译的时间消耗。同时,它还应用了一些代码优化模式,使得代码执行更快。从而加速PHP的执行。
安装
yum install php72w-opcache -y
官方推荐配置
opcache.enable=1opcache.memory_consumption=128opcache.interned_strings_buffer=8opcache.max_accelerated_files=4000opcache.revalidate_freq=60opcache.fast_shutdown=1opcache.enable_cli=1
测试PHP动态页面
[root@localhost php.d]# ab -c 1000 -n 100000 http://192.168.154.140/test.phpThis is ApacheBench, Version 2.3 <$Revision: 1430300 $>Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking 192.168.154.140 (be patient)Completed 10000 requestsCompleted 20000 requestsCompleted 30000 requestsCompleted 40000 requestsCompleted 50000 requestsCompleted 60000 requestsCompleted 70000 requestsCompleted 80000 requestsCompleted 90000 requestsCompleted 100000 requestsFinished 100000 requestsServer Software: nginxServer Hostname: 192.168.154.140Server Port: 80Document Path: /test.phpDocument Length: 73746 bytesConcurrency Level: 1000Time taken for tests: 43.004 secondsComplete requests: 100000Failed requests: 0Write errors: 0Total transferred: 7392500000 bytesHTML transferred: 7374600000 bytesRequests per second: 2325.39 [#/sec] (mean)Time per request: 430.036 [ms] (mean)Time per request: 0.430 [ms] (mean, across all concurrent requests)Transfer rate: 167875.33 [Kbytes/sec] receivedConnection Times (ms)min mean[+/-sd] median maxConnect: 1 78 54.3 67 524Processing: 38 350 80.6 343 824Waiting: 1 51 33.8 44 404Total: 112 428 77.3 405 899Percentage of the requests served within a certain time (ms)50% 40566% 42075% 43580% 44990% 50495% 59598% 69499% 767100% 899 (longest request)
Nginx Rewrite
现在 Nginx 已经成为很多公司作为前端反向代理服务器的首选,在实际工作中往往会遇到很多跳转(重写URL)的需求。比如更换域名后需要保持旧的域名能跳转到新的域名上、某网页发生改变需要跳转到新的页面、网站防盗链等等需求。 如果在后端使用的Apache服务器,虽然也能做跳转,规则库也很强大,但是用Nginx跳转效率会更高, 这也是学习本章的目的所在。
Rewrite前置知识
1、Rewrite跳转场景
Rewrite跳转场景主要包括以下几种:
- 可以调整用户浏览的URL,看起来更规范,合乎开发及产品人员的需求;
- 为了让搜索引擎搜录网站内容及用户体验更好,企业会将动态URL地址伪装成静态地址提供服务;
- 网址换新域名后,让旧的访问跳转到新的域名上。例如,访问京东的 360buy.com会跳转到 jd.com;
- 根据特殊变量、目录、客户端的信息进行URL调整等。
2、Rewrite跳转实现
Nginx 是通过 ngx_http_rewrite_module模块支持url重写、支持if条件判断,但不支持 else。另外该模块需要PCRE支持,应在编译Nginx时指定PCRE支持,默认已经安装。根据相关变量重定向和选择不同的配置, 从一个 location 跳转到另一个location,不过这样的循环最多可以执行10次,超过后Nginx将返回500错误。同时,重写模块包含set指令,来创建新的变量并设其值,这在有些情景下非常有用的,如记录条件标识、传递参数到其他location、记录做了什么等等。rewrite功能就是,使用Nginx提供的全局变量或自己设置的变量, 结合正则表达式和标志位实现url 重写以及重定向。
3、Rewrite实际场景
在实际工作场景,Nginx跳转需求有三种方式可实现。可以直接用rewrite进行匹配跳转,也可以使用if匹配全局变量后跳转,另外还可以使用location匹配再跳转,所以rewrite只能放在server{},if{},location{}段中,例如location只能对域名后边的除去传递的参数外的字符串起作用,例如http://www.domain.com/index.php?id=1只对/index.php重写。如果想对域名或参数字符串起作用, 可以使用if全局变量匹配, 也可以使用proxy_pass反向代理。
Rewrite必备知识
1、正则表达式
学习Rewrite之前要对正则表达式要很熟悉,下表中列举出一些常用的正则表达式元字符。要深刻理解和学习每个元字符的含义,并且多动手进行实验,在实际生产环境中要结合多个元字符一起使用。
| 字符 | 描述 |
|---|---|
| \ | 将下一个字符标记为一个特殊字符,或一个原义字符,或一个向后引用,或一个八进制转义符。例如,”\n”匹配一个换行符。 |
| ^ | 匹配输入字符串的开始位置 |
| $ | 匹配输入字符串的结束位置 |
| * | 匹配前面的子表达式重复零次或多次,等价于{0,} |
| + | 匹配前面的子表达式重复一次或多次,等价于{1,} |
| ? | 匹配前面的子表达式重复零次或一次,等价于{0,1} |
| ? | 当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少地匹配所搜索的字符串, 而默认的贪婪模式则尽可能多地匹配所搜索的字符串。 例如,对于字符串”oooo”,”o+?”将匹配单个”o”,而”o+”将匹配所有的”o”。 |
| {n} | n是一个非负整数,匹配确定的n次。 |
| {n,} | n是一个非负整数,至少匹配n次 |
| {n,m} | m和n均为非负整数,其中n<=m,最少匹配n次且最多匹配m次 |
| . | 匹配除”\n”之外的任何单个字符。要匹配包括”\n”在内的任何字符,请使用像”[.\n]”的模式 |
| (pattern) | 匹配pattern并获取这一匹配 |
| (?:pattern) | 匹配pattern但不获取匹配结果。这在使用“或”字符(|)来组合一个模式的各个部分是很有用的。例如:’industry|industries’就可以用 ’industr(?:y|ies)’代替 |
| (?=pattern) | 正向预查,在任何匹配pattern的字符串开始处匹配查找字符串。例如:”Windows(?=95|98|NT|2000)”能匹配”Windows2000”中 的”Windows”,但不能匹配”Windows3.1”中的”Windows”。 |
| (?!pattern) | 负向预查,在任何不匹配pattern的字符串开始处匹配查找字符串。例如:”Windows(?!95|98|NT|2000)”能匹配”Windows3.1”中 的”Windows”,但不能匹配”Windows2000”中的”Windows”。 |
| x|y | 匹配x或y |
| [xyz] | 字符集合,匹配所包含的任何一个字符 |
| [^xyz] | 负值字符集合,匹配未包含的任意字符 |
| [a-z] | 字符范围,匹配指定范围内的任意字符 |
| [^a-z] | 负值字符范围,匹配任何不在指定范围内的任意字符 |
| \b | 匹配一个单词边界,也就是单词和空格间的位置 |
| \B | 匹配非单词边界 |
| \cx | 匹配由x指明的控制字符。x的值必须为A-Z或a-z之间 |
| \d | 匹配一个数字字符。等价于[0-9] |
| \D | 匹配一个非数字字符。等价于[^0-9] |
| \f | 匹配一个换页符。等价于\x0c和\cL |
| \n | 匹配一个换行符。等价于\x0a和\cJ |
| \r | 匹配一个回车符。等价于\x0d和\cM |
| \s | 匹配任何空白字符,包括空格、制表符、换页符等 |
| \S | 匹配任何非空白符 |
| \t | 匹配一个制表符 |
| \w | 匹配包括下划线的任何单词字符。等价于[a-zA-Z0-9_] |
| \W | 匹配任何非单词字符 |
| \xn | 匹配n,其中n为十六进制转义值。例如”\x41”匹配”A” |
| \num | 匹配num,其中num是一个正整数。对所获取的匹配的引用。例如:”(.)\1” |
2、Rewrite语法
Syntax: rewrite regex replacement [flag];Default: —Context: server, location, if
如果regex匹配了一个请求的URI,该URI被替换为replacement。rewrite 指令在配置文件中按照出现的顺序执行。可使用flag中止进一步的处理。如果replacement以“http://”,“https://”为起始的字符串,将中止处理,并返回重定向指令给客户端。
flag参数的值可以为:
- last 停止当前ngx_http_rewrite_module模块指令集的处理,并为修改后的URI寻找新的匹配的location
- break 停止当前ngx_http_rewrite_module模块指令集的处理,与break指令作用相同,本条规则匹配完成即终止,不再匹配后面的任何规则
- redirect 返回302代码的临时重定向,当replacement不以“http://”,“https://”为起始的字符串时使用。浏览器地址会显示跳转后的URL地址,爬虫不会
更新url(因为是临时) - permanent 返回301代码的永久重定向。浏览器地址栏会显示跳转后的 URL 地址,爬虫更新url。
如果后面不跟flag标记,那么默认是302临时重定向。在实际工作场景中,还有另一种return指定。因为301和302不能简单的只返回状态码,还必须有重定向的URL,这就是return指令无法返回301,302的原因了。
例子:
server {...rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra last;return 403;...}
但如果这些指令被放入“/download/” location区块中,应将last flag替换为break,否则nginx会不断循环,达到10次后,返回500 error
location /download/ {rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 break;rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra break;return 403;}
last一般写在server和if中,而break一般使用在location中。last不终止重写后的url匹配,即新的url会再从server走一遍匹配流程,而break终止重写后的匹配。
如果replacement包含请求参数,原来的请求参数将被追加在后面。如果不希望追加原来的请求参数,可在replacement字符串的末尾添加一个“?”符号,例如:
rewrite ^/users/(.*)$ /show?user=$1? last;
3、location
Syntax: location [ = | ~ | ~* | ^~ ] uri { ... }location @name { ... }Default: —Context: server, location
根据请求的URI设置配置。
在一个server中location配置段可存在多个,用于实现URI到文件系统的路径映射;
匹配字符串分为两种:普通字符串(literal string)和正则表达式(regular expression),其中 ~ 和 ~* 用于正则表达式, 其他前缀和无任何前缀都用于普通字符串。
匹配顺序是:
- 先匹配普通字符串,将最精确的匹配暂时存储;
- 然后按照配置文件中的声明顺序进行正则表达式匹配,只要匹配到一条正则表达式,则停止匹配,取正则表达式为匹配结果;
- 如果所有正则表达式都匹配不上,则取1中存储的结果;
- 如果普通字符串和正则表达式都匹配不上,则报404 NOT FOUND
- “^~ ”和“= ”都能阻止继续搜索正则location。不同点是“^~”依然遵守“最大前缀”匹配规则,然而“=”不是“最大前缀”,而是必须是严格匹配
- 只要遇到“精确匹配exact match ”,即使普通location 没有带“= ”或“^~ ”前缀,也一样会终止后面的匹配。例如:
location = /uri =开头表示精确前缀匹配,只有完全匹配才能生效。location ^~ /uri ^~开头表示普通字符串匹配上以后不再进行正则匹配。location ~ pattern ~开头表示区分大小写的正则匹配。location ~* pattern ~*开头表示不区分大小写的正则匹配。location /uri 不带任何修饰符,表示前缀匹配。location / 通用匹配,任何未匹配到其他location的请求都会匹配到。
配置举例:
location = / {[ configuration A ]}location / {[ configuration B ]}location /documents/ {[ configuration C ]}location ^~ /images/ {[ configuration D ]}location ~* \.(gif|jpg|jpeg)$ {[ configuration E ]}#“/” 请求匹配configuration A;#“/index.html”请求匹配configuration B;#“/documents/document.html”请求匹配configuration C;#“/images/1.gif”请求匹配configuration D;#“/documents/1.jpg”请求匹配configuration E。#注意:正则匹配会根据匹配顺序,找到第一个匹配的正则表达式后将停止搜索。#普通字符串匹配则无视顺序,只会选择最精确的匹配。
注:从功能看rewrite和location似乎有点像,都能实现跳转,主要区别在于rewrite是在同一域名内更改获取资源的路径,而location是对一类路径做控制访问或反向代理,还可以proxy_pass到其他机器。很多情况下rewrite也会写在 location里。
Rewrite配置案例
YUM安装Nginx
安装完成后,修改配置文件如下:
server {listen 80;server_name www.domain.com;#charset koi8-r;access_log /var/log/nginx/www.domain.com-access.log main;location / {root /opt/nginx/html;index index.html index.htm;}........ #省略部分内容}
注意事项: 做每一步场景测试之前请确定这个域名可以正常解析,每做下一个场景之前请删除上一个场景的配置,另外清除浏览器缓存。
基于域名的跳转
现在公司旧域名 www.domain.com有业务需求有变更,需要使用新域名 www.newdomain.com代替,但是旧域名不能废除,需要跳转到新域名上,而且后面的参数保持不变。
在/etc/nginx/conf.d/default.conf文件里的location /下面添加如下内容:
server {listen 80;server_name www.newdomain.com www.domain.com ;#charset koi8-r;access_log /var/log/nginx/www.domain.com-access.log main;location / {root /opt/nginx/html;index index.html index.htm;if ($host = 'www.domain.com') {rewrite ^/(.*)$ http://www.newdomain.com/$1 permanent;}}}
修改配置文件后,重启nginx服务
使用客户端浏览器访问旧域名,域名直接跳转,按F12可以清楚的看到从旧域名 www.domain.com 跳转到了新域名 www.newdomain.com 上,状态码是301 永久重定向。

域名后面加参数跳转,因为在代码中很多的请求是带参数的,所以要保证参数都能正常跳转。 浏览器输入模拟访问 http://www.domain.com/test/1/index.php(虽然这个请求内容是
不存在的)跳转到 http://www.newdomain.com/test/1/index.php, 从 headers 里面可以看到301实现了永久重定向跳转,而且域名后的参数也正常跳转。

基于客户端IP访问跳转
例如今天公司业务版本上线,所有IP访问任何内容都显示一个固定维护页面, 只有公司IP访问正常。
在/etc/nginx/conf.d/default.conf 文件里添加如下内容
server {listen 80;server_name www.newdomain.com www.domain.com ;#charset koi8-r;access_log /var/log/nginx/www.domain.com-access.log main;# 下面是添加的内容set $rewrite true;if ($remote_addr = '192.168.154.1') {set $rewrite false;}if ($rewrite = true) {rewrite (.+) /maintenance.html;}location = /maintenance.html {root /opt/nginx/html;}....... #省略很多内容}[root@www conf.d]# echo 'Website is Maintaining, Please visit later!' > /opt/nginx/html/maintenance.html[root@www conf.d]# systemctl restart nginx
只有 IP 为192.168.154.1能正常访问,其它地址都是维护页面,使用一个局域网的其它IP地址用浏览器访问 http://www.domain.com 域名和加参数都是 请求的maintenance.html页面的内容, 而且状态码是 200,

基于旧域名跳转到新域名后面加目录
例如现在访问的是 http://bbs.domain.com,现在需要将这个域名下面的发帖都跳转到 http://www.domain.com/bbs, 注意保持域名跳转后的参数不变。
修改/etc/nginx/conf.d/default.conf 配置文件如下:
server {listen 80;server_name www.newdomain.com www.domain.com bbs.domain.com ;#charset koi8-r;access_log /var/log/nginx/www.domain.com-access.log main;location / {root /opt/nginx/html;index index.html index.htm;if ($host = 'www.domain.com') {rewrite ^/(.*)$ http://www.newdomain.com/$1 permanent;}}location /post {rewrite (.+) http://www.domain.com/bbs$1 permanent;}}
模拟使用浏览器访问 http://bbs.domain.com/post/1.php ,跳转到 http://www.newdomain.com/bbs/post/1.php

基于参数匹配的跳转
例如现在访问 http://www.domain.com/100-(100|200)-100.html-100.html) 跳转到 http://www.domain.com 页面
编辑/etc/nginx/conf.d/default.conf 文件里添加如下内容:
location ~* /100-(100|200)-(\d+).html$ {rewrite (.*) http://www.domain.com permanent;}
重启服务器后,使用浏览器访问 http://www.domain.com/100-200-100.html

基于目录下所有php结尾的文件跳转
访问 http://www.domain.com/upload/1.php 跳转到首页
编辑/etc/nginx/conf.d/default.conf 文件里添加如下内容:
location ~* /upload/.*\.php$ {rewrite (.+) http://www.domain.com permanent;}
重启服务,浏览器访问 http://www.domain.com/upload/1.php即可实现跳转
基于最普通一条url请求的跳转,访问一个具体的页面跳转到首页
编辑/etc/nginx/conf.d/default.conf 文件里添加如下内容:
location ~* ^/1/test.html {rewrite (.+) http://www.domain.com permanent;}
重启服务后,浏览器访问 http://www.domain.com/1/test.html 跳转到首页
总结:
关于 Nginx rewrite本章的内容就这么多。其实在实际工作中远远不止这些场景, 而且会更加复杂繁琐, 希望同学们能举一反三, 多加练习。
