nginx总结第四章----nginx模块与指令详解

四 nginx模块

官方提供了5个类型的模块:核心模块、配置模块、事件模块、http模块、mail模块。
    配置模块主要负责解析nginx.conf文件,是其他模块的基础,该类模块中只有一个ngx_conf_module模块;
    核心模块主要负责定义除配置模块之外的其他模块,该类模块中有6个核心模块。
        ngx_mail_module负责定义mail模块;
        ngx_http_module负责定义http模块;
        ngx_events_module负责定义事件模块;
        ngx_core_module则是nginx启动加载的第一个模块,它主要用来保存全局配置项。
        ngx_openssl_module只有当加载了之后,nginx才支持https请求
        ngx_errlog_module
    事件模块即负责事件的注册、分发处理、销毁等,该类模块中主要有这几个模块:
        ngx_event_core_module负责加载其他事件模块,是其他事件模块的基础
        ngx_epoll_module,该模块则是我们后面需要重点分析的模块,它负责事件的注册、集成、处理等
        其他的模块比如ngx_kqueue_module这些我们后面基本不会涉及,就不解释了,毕竟是另外一种I/O多路复用机制,大致的思想是一样的
    http模块和mail模块也无需太多解释,等到后面再介绍。

image

4.1 核心模块

  1. ngx_core_module
  2. ngx_http_module
  3. ngx_event_module
  4. ngx_stream_module
  5. ngx_mail_module

4.2 http模块

4.2.1 ngx_http_core_module

  • 指令1: root和alias
配置root和alias,测试访问的资源路径。
root:
(1) 前缀匹配
    location /download1/ {
        root /usr/local/mywork/test/html;
    }
    或者:
    location /download1/ {
        root /usr/local/mywork/test/html/;
    }
    或者:
    location /download1 {
        root /usr/local/mywork/test/html;
    }
    或者:
    location /download1 {
        root /usr/local/mywork/test/html/;
    }
(2) 正则匹配
    location ~ ... 重复上述四种情况,
以上八种情况:
curl -x 127.0.0.1:80 static.test.com/download1/1.html
    ==> /usr/local/mywork/test/html/download1/1.html
curl -x 127.0.0.1:80 static.test.com/download1/zhangbao/1.html
    ==> /usr/local/mywork/test/html/download1/zhangbao/1.html

总结: root不论哪种匹配方式,不论root最后加没加/,访问的都是root_path+uri


alias:
    浏览器访问:http://test.com/download2/zhangbao/1.html
(1) 前缀匹配:
    location  /download2/ {
        alias /usr/local/mywork/test/html;
    }
    location  /download2/ {
        alias /usr/local/mywork/test/html/;
    }
    location  /download2 {
        alias /usr/local/mywork/test/html;
    }
    location  /download2 {
        alias /usr/local/mywork/test/html/;
    }
===> 以上四种情况: 
/usr/local/mywork/test/htmlzhangbao/1.html
/usr/local/mywork/test/html/zhangbao/1.html
/usr/local/mywork/test/html/zhangbao/1.html
/usr/local/mywork/test/html//zhangbao/1.html

(2) 正则匹配: 
    location ~ /download2/ {
        alias /usr/local/mywork/test/html;
    }
    location ~ /download2/ {
        alias /usr/local/mywork/test/html/;
    }
    location ~ /download2 {
        alias /usr/local/mywork/test/html;
    }
    location ~ /download2 {
        alias /usr/local/mywork/test/html/;
    }
===> 以上四种情况:
1和3: 
    403错误:日志显示 directory index of "/usr/local/mywork/test/html" is forbidden,request: "GET /download/zhangba/1.html/ HTTP/1.1"
2和4: 
    301无限重定向:浏览器地址栏目是:http://test.com/download2/web/1.html/index.html/index.html/index.html/index.html/index.html/index.html/index.html/index.html/index.html/index.html/index.html/index.html/index.html/index.html/index.html/index.html/index.html/index.html/
    
解释:
    1和3: 当配置的server或者location没有指定首页时,找不到文件,会报403错误。
    2和4static模块实现了root/alias功能时,发现访问目标是目录,但URL末尾未加/时,会返回301重定向。   
    absolute_redirect,port_in_redirect,server_name_in_redirect 可以控制
    
总结:
看来对于alias来说,用不带修饰符的前缀匹配方式比较合适,而且处理逻辑和proxy_pass的一样,将匹配中的部分去掉后再拼接
而alias不适合用正则匹配,可能有意想不到的错误。
  • 指令2: client_*
client_body_buffer_size  : 请求存在包体时,接收包体时所分配的内存
	Syntax: client_body_buffer_size size;
   Default: client_body_buffer_size 8k|16k;	
   Context: http, server, location
   如果接收头部时就已经接收到了完整的包体,则这段内存不会被分配
   如果剩余未接收的包体的长度小于client_body_buffer_size的大小,则仅分配所需的大小
   如果剩余未接收的包体的长度大于client_body_buffer_size的大小,则分配client_body_buffer_size大的空间接收body
   	当关闭body缓存时,则该内存上的内容立即会被发往上游,一段一段的收,一段一段的发。
   	当开启body缓存时,该段内存用完时,写入临时文件,并释放这段内存。
   	
client_body_in_single_buffer		
   	Syntax: client_body_in_single_buffer on | off;
   	Default: client_body_in_single_buffer off;
   	Context: http, server, location

client_max_body_size: 包体最大长度限制
   	Syntax: client_max_body_size size;
   	Default: client_max_body_size 1m;
   	Context: http, server, location
       仅对请求头部中含有Content-Length生效
       超出最大长度限制,返回413错误。
   	
client_body_temp_path :临时文件路径
   	Syntax: client_body_temp_path path [level1 [level2 [level3]]];
   	Default: client_body_temp_path client_body_temp;
   	Context: http, server, location
   	默认值是client_body_temp,即将超出client_body_buffer_size 的body存在这个目录下。
   	设置多级目录是为了防止一个目录下文件过多,文件的存取速度太慢。
   	
client_body_in_file_only on	:决定body是否写入文件,一般为了定位问题而配置的	
   	Syntax: client_body_in_file_only on | clean | off;
   	Default: client_body_in_file_only off;
   	Context: http, server, location
   	on: 用户上传的body会一直保留在文件中,请求处理完成后也会一直保留,文件不会被删除。
   	clean:只要有body,用户上传的body必须写入文件,但是请求完成后文件就会被删除。
   	off:如果body较小,用client_body_buffer_size大小的内存就能存下,则此body不会被写入文件中
   	
client_body_timeout time : 两次读取body之间的最大迟延,类似于tcp的keepalive_timeout的超时时间
   	Syntax: client_body_timeout time;
   	Default: client_body_timeout 60s;
   	Context: http, server, location
   	读取包体超时,则返回408错误。

4.2.2 autoindex模块

展示目录结构
    server {
        server_name autoindex.test.com;
        location / {
            alias /usr/local/mywork/test/;
            autoindex on;    
            autoindex_exact_size off;   
            autoindex_format html;
            autoindex_localtime on;
        }
    }

4.2.3 ngx_http_proxy_module

  • 作用:实现反向代理及缓存功能
  • 配置范例
  location / {
      proxy_pass http://github.com;
      proxy_redirect off;
      proxy_set_header HOST $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
  • 指令1 :proxy_*
1 proxy_redirect : 修改返回的location的头部
        语法:proxy_redirect [ default|off|redirect replacement ] 
        默认值:proxy_redirect default 
        使用字段:http, server, location 
        如果需要修改从被代理服务器传来的应答头中的"Location"和"Refresh"字段,可以用这个指令设置。
        假设被代理服务器返回Location字段为: http://localhost:8000/two/some/uri/
        这个指令: 
        proxy_redirect http://localhost:8000/two/  http://frontend/one/;
        将Location字段重写为http://frontend/one/some/uri/。
        参考连接:https://blog.csdn.net/u010391029/article/details/50395680

2 proxy_set_header :
        上下文: http、server、location
        默认:  proxy_set_header Host $proxy_host;
               proxy_set_header Connection close;
        注意:
        (1)http段,server段,location段同时配置了proxy_set_header时,只有location中会生效,例如:
		        http{
		            proxy_set_header xxx1 A
		            proxy_set_header xxx2 B
		            location / {
		                proxy_set_header xxx3 C
		            }
		        }
		        A和B都不会生效,除非去除C!
		(2) 若value的值为空(‘ ’),则整个header都不会向上游发送

3  proxy_method 
 	Syntax: proxy_method method;
	Default: —
	Context: http, server, location

4  proxy_http_version
	Syntax: proxy_http_version 1.0 | 1.1;
	Default: proxy_http_version 1.0;
	Context: http, server, location

5  proxy_pass_request_headers
		Syntax: proxy_pass_request_headers on | off;
		Default: proxy_pass_request_headers on;
		Context: http, server, location
		
6 proxy_pass_request_body 和 proxy_set_body
		生成发往上游的包体
		Syntax: proxy_pass_request_body on | off;
		Default: proxy_pass_request_body on;
		Context: http, server, location

		Syntax: proxy_set_body value;
		Default: —
		Context: http, server, location

7 proxy_request_buffering  :控制接收完完整包体再转发或者是边收边发。
		Syntax: proxy_request_buffering on | off;
		Default: proxy_request_buffering on;
		Context: http, server, location
		默认情况下是接收完完整包体再转发。

8 proxy_connect_timeout :建立tcp连接的时间 
		Syntax: proxy_connect_timeout time;
		Default: proxy_connect_timeout 60s;
		Context: http, server, location
		如果规定时间内三次握手不成功,未能建立连接,则会返回给客户端502
	
9    proxy_next_upstream : 发生错误时尝试与下一个上游服务器转发请求。 
		Syntax: proxy_next_upstream http_502 | ..;
		Default: proxy_next_upstream error timeout;
		Context: http, server, location

10 	proxy_socket_keepalive 
		Syntax: proxy_socket_keepalive on | off;
		Default: proxy_socket_keepalive off;
		Context: http, server, location
		on时会使用操作系统默认的tcp keepalive相关的配置进行探测,及时关掉不再使用的的tcp连接。

11 proxy_buffering  
		Syntax: proxy_buffering on | off;
		Default: proxy_buffering on;
		Context: http, server, location
	    默认开启,先接收完完整的包体,然后再向客户端返回

12 proxy_buffer_size  接收上游的header响应头部
		Syntax: proxy_buffer_size size;
		Default: proxy_buffer_size 4k|8k;
		Context: http, server, location
		proxy_buffer_size 有一点特殊在于,无论 proxy_buffering 是否开启,proxy_buffer_size 都会起作用。指定后端 response 的 buffer 的大小。它是来自后端 response 的一部分,它包含 Headers,从 response 分离出来。它仅用于限定 headers 的 buffer 区,所以它的值比 proxy_buffers 更低。
		如果上游的响应头部超过此限制,则会有错误日志:
		error.logupstream sent too big header
	
13 proxy_buffers  定义接收上游的http包体的内存大小
		Syntax: proxy_buffers number size;
		Default: proxy_buffers 8 4k|8k;
		Context: http, server, location
		如果这段内存能够存放下包体,则不会再向磁盘中写入。

14  proxy_max_temp_file_size 和 proxy_temp_file_write_size 和proxy_temp_path  
	Syntax: proxy_max_temp_file_size size;   定义写入body的文件最大size
	Default: proxy_max_temp_file_size 1024m;
	Context: http, server, location

	Syntax: proxy_temp_file_write_size size;   定义每次写入多少
	Default: proxy_temp_file_write_size 8k|16k;
	Context: http, server, location

	Syntax: proxy_temp_path path [level1 [level2 [level3]]];  定义临时文件的路径和级别
	Default: proxy_temp_path proxy_temp;
	Context: http, server, location
	
15 proxy_busy_buffers_size :及时的转发包体 
		Syntax: proxy_busy_buffers_size size;
		Default: proxy_busy_buffers_size 8k|16k;
		Context: http, server, location
		
16 proxy_read_timeout 定义两次读取上游响应的超时时间
		Syntax: proxy_read_timeout time
		Default: proxy_read_timeout 60s;
		Context: http, server, location
17 proxy_limit_rate  限制读取上游的响应的速率
		Syntax: proxy_limit_rate rate
		Default: proxy_limit_rate 0;
		Context: http, server, location
		
18 proxy_store_access 和proxy_store 上游包体的持久化
		Syntax: proxy_store_access users:permissions ...;
		Default: proxy_store_access user:rw;
		Context: http, server, location
		
		Syntax: proxy_store on | off | string;
		Default: proxy_store off;
		Context: http, server, location

19    proxy_ignore_headers 禁用上游响应头部的功能
		Syntax: proxy_ignore_headers field ...;
		Default: —
		Context: http, server, location
		功能:有些响应头可以改变nginx的行为,该指令能够禁止她们生效
		可以禁用的头部:
			X-Accel-Redirect : 由上游服务器指定nginx内部重定向,控制请求执行
			X-Accel-Limit-rate :由上游服务器控制发往客户端的速率,等同于limit_rate指令
			X-Accel-Buffering   : 由上游控制是否缓存上游响应
			X-Accel-Charset : 由上游控制Content-Type中的Charset
			缓存相关:
					X-Accel-Expires:设置响应在nginx中的缓存时间,单位为秒;@开头表示一天中的某一时刻
					Expires: 控制nginx的缓存时间,优先级低于X-Accel-Expires
					Cache-Control:控制nginx缓存时间,优先级低于X-Accel-Expires
					Set-Cookies:响应中出现Set-Cookie则不缓存,可通过proxy_ignore_headers禁止生效
					Vary:响应中出现Vary:*则不缓存,可通过proxy_ignore_headers禁止生效

20 proxy_hide_header 转发上游的响应 
			Syntax: proxy_hide_header field;
			Default: —
			Context: http, server, location
			功能:对于上游响应中的某些头部,设置不向客户端转发
			默认不转发的头部:
				Date:  由ngx_http_header_filter_module过滤模块填写,值为nginx发送响应头部的时间
				Server: 由ngx_http_header_filter_module过滤模块填写,值为nginx的版本号
				X-Pad :通常是Apache为避免浏览器的bug生成的头部,默认忽略
				X-Accel- :用户控制nginx的行为,不需要向客户端转发

22 proxy_pass_header 对于被proxy_hide_header的头部,设置向下游转发
		Syntax: proxy_pass_header field;
		Default: —
		Context: http, server, location

23    proxy_next_upstream 
		Syntax: proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_503 |
		http_504 | http_403 | http_404 | http_429 | non_idempotent | off ...;
		Default: proxy_next_upstream error timeout;
		Context: http, server, location
		前提: 没有向客户端发送任何内容
		
		限制proxy_next_upstream的时间与次数
		Syntax: proxy_next_upstream_timeout time;
		Default: proxy_next_upstream_timeout 0;
		Context: http, server, location
		
		Syntax: proxy_next_upstream_tries number;
		Default: proxy_next_upstream_tries 0;
		Context: http, server, location
24    proxy_intercept_errors 用error_page拦截上游失败的响应
		Syntax: proxy_intercept_errors on | off;
		Default: proxy_intercept_errors off;
		Context: http, server, location
		作用: 当上游的响应的状态码大于等于300时,将响应返回客户端还是按error_page指令处理
		如果不开启,则当响应为403,404, 500等错误时,会原封不动的返回给客户端
		如果开启,则可以通过定义error_page将错误页面进行修饰后返回给客户端:  error_page 500  1.html
	
		
23  缓存指令proxy_cache
ngxin缓存功能只需要proxy_cache_path和proxy_cache两个指令就可开启。但是大型的网站中,nginx的缓存功能用的不多,而是用更加专业的缓存varnish和memache 

		开启与关闭:   
		Syntax:	proxy_cache zone | off;   
		Default:   	
		proxy_cache off;   
		Context:	http, server, location 
   
缓存路径:
	proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=mycache:10m max-size=10g inactive=60m;   
则缓存文件可能形式为:/data/nginx/cache/c/29/b7f54b2df7773722d382f4809d65029c   

配置范例:
location /{
	proxy_cache mycache;
	proxy_cache_valid 200 1d;  //设置缓存有效时间
	proxy_cache_valid 302 1h;
	proxy_cache_valid any 10m;
	proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;  //在上述情况下使用它不新鲜的缓存,没有总比陈旧强
	proxy_cache_method GET 只对GET方法缓存
    proxy_cache_min_uses 10; 至少被访问10,才被缓存
    proxy_cache_bypass string; 设置在何种情况下ngxin不从缓存中取数据,一般私有数据不能用公共缓存  $cookie_nocache $arg_nocache $http_authorization 
    
    proxy_pass http://10.99.2.15;
	proxy_set_header X-Real-Ip $remote_addr
}
  • 踩过的坑:
浏览器:http://test.proxy.com/test/science/getinfo?a=1&b=2
(1)     location ~ /test/(.*) {
             proxy_pass http://10.99.1.51;
        upstream接收到的请求:/test/science/getinfo?a=1&b=2

(2)    location ~ /test/(.*) {
             proxy_pass http://10.99.1.51/;
        }
        upstream test_up{
            server 10.99.1.51;
        }
        location ~ /test {
             proxy_pass http://test_up/;
        }
        nginx启动报错:
        nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression, or inside named location, or inside "if" statement, or inside "limit_except" block in /usr/local/mywork/gateway/orange/conf/vhosts/test.balancer.com.conf:24

(3)    location ~ /test/(.*) {
             set $new_url $1$is_args$args;
             proxy_pass http://10.99.1.51/$new_url;
		}
        upstream接收到的请求:/science/getinfo?a=1&b=2
        
(4)     location ~ /test/(.*) {
             set $new_url $1$is_args$args;
             proxy_pass http://10.99.1.51/$new_url/;
		}
        upstream接收到的请求:/science/getinfo?a=1&b=2/

(5)    location ~ /test/(.*) {
             set $new_url $1$is_args$args;
             proxy_pass http://10.99.1.51/$request_uri;
		}
        upstream接收到的请求://test/science/getinfo?a=1&b=2
        注意这里有两条/,$request_uri中本身包含了一个

(6)    location ~ /test/(.*) {
             set $new_url $1$is_args$args;
             proxy_pass http://10.99.1.51/$request_uri;
        }  
        upstream接收到的请求:/test/science/getinfo?a=1&b=2

现在改成不带任何修饰符的前缀匹配:
浏览器:http://test.proxy.com/test/science/getinfo?a=1&b=2
(1)
        location  /test/ {
             proxy_pass http://10.99.1.51;
             
        upstream接收到的请求:/test/science/getinfo?a=1&b=2
(2)     
        location  /test/ {
             proxy_pass http://10.99.1.51/;
             
        upstream接收到的请求:/science/getinfo?a=1&b=2
(3)
        upstream test_up{
            server 10.99.1.51;
        }
        location  /test/ {
             proxy_pass http://test_up;
             
        upstream接收到的请求:/test/science/getinfo?a=1&b=2
(4)  
        upstream test_up{
            server 10.99.1.51;
        }
        location  /test/ {
             proxy_pass http://test_up/;
             
        upstream接收到的请求:/science/getinfo?a=1&b=2
(5)
       upstream test_up{
            server 10.99.1.51;
        }
        location  /test {
             proxy_pass http://test_up/;
             
        upstream接收到的请求://science/getinfo?a=1&b=2
        
(6)        
       upstream test_up{
            server 10.99.1.51;
        }
        location  /test {
             proxy_pass http://test_up;
             
        upstream接收到的请求:/test/science/getinfo?a=1&b=2
(7) 浏览器访问:http://test.proxy.com/zhangbao/test/science/getinfo?a=1&b=2
    结果是这些location都匹配不中,因为前缀都匹配不上

(8)   浏览器访问:http://test.proxy.com/zhangbao/test/science/getinfo?a=1&b=2

       upstream test_up{
            server 10.99.1.51;
        }
        location ~ /test {
             proxy_pass http://test_up;
             
        upstream接收到的请求:/zhangbao/test/science/getinfo?a=1&b=2
    这里就不是前缀匹配了,只要uri里有/test字段就可以匹配中


现在将后端upstream name 写成变量的形式:
浏览器:http://test.proxy.com/test/science/getinfo?a=1&b=2
配置如下:
        location  /test/ {
             set $ups zhouzhongtao2;
             proxy_pass http://$ups;
        或者:
        location  ~ /test/ {
             set $ups zhouzhongtao2;
             proxy_pass http://$ups;
        
        upstream接收到的请求: /test/science/getinfo?a=1&b=2
        
        location  /test/ {
             set $ups zhouzhongtao2;
             proxy_pass http://$ups/;
        
        location ~ /test/ {
             set $ups zhouzhongtao2;
             proxy_pass http://$ups/;
        upstream接收到的请求:/

总结:
    对于 ~ 匹配: 
        只要语法不错误,而且匹配中了,直接往后端扔给全部的uri
    对于不带修饰符的前缀匹配:
        如果写成proxy_pass http://upstream_name
        加根:转发给后端时掐掉匹配中的部分
        不加根:转发给后端的时候带上匹配中的部分。
    对于将upstream写成变量形式的,不管是~匹配黑市不带修饰符的前缀匹配
        不加根:全量uri转发到后端
        加根: 访问的是根,即uri = /

4.2.4 ngx_http_access_module

  • 生效阶段: NGX_HTTP_ACCESS_PHASE
  • 配置语法
1 allow/deny
    Syntax:	allow address | CIDR | unix: | all;
    Default:	—
    Context:	http, server, location, limit_except
    
    其中address:某个ip
        CIDR:某个ip段
        unix:基于socket的限制
        all: 以上所有的
    在location、server、http不同地方配置访问控制,生效的范围不一样
    

4.2.5 auth basic authenication

  • 加密协议: RFC2617: HTTP BASIC Authentication
  • 生效阶段 access阶段
  • 执行流程:
1 用户请求 ---> Nginx
2 Nginx返回401 Unauthorized,并在header头中加上WWW-Authenication:Basic
3 改错误浏览器不会显示,而是弹出输入框,输入用户名和密码。
4 浏览器将用户密码以明文的方式发送给Nginx,如果是https,则会加密。
  • 相关指令
    auth_basic string|off  :定义第二步中的header头
    auth_basic_user_file file;  定义存储用户名和密码的文件
        生成改file的方法:
            1) 安装Apache的http-tools
            2) htpasswd -c file -b user pass
            

4.2.6 ngx_http_upstream_module

  • 作用:定义服务器组

调用服务器组的方法:proxy_pass fastcgi_pass uwsgi_pass

  • nginx支持的调度算法(六种):
轮询(默认)
ip_hash
url_hash
hash:包括普通hash和c hash
least_conn
fair:智能选择,选择响应耗时短的自动分配
  • 指令集:
每个指令对应一个模块处理
Directives
     upstream
     server
     zone
     state
     hash
     ip_hash
     keepalive  
     ntlm
     least_conn  :调度方法,指明最少连接
     least_time
     queue
     sticky
     sticky_cookie_insert //和sticky指令二选一使用

指令1: proxy_pass

注意:后面要指定协议(http://不能掉)

配置范例:
upstream upservers {
    server 10.99.2.15       weight=5;    
    server 10.99.2.122       weight=2;
    server admin.xesv5.com       weight=2;

    server backend2.example.com:8080;
    server unix:/tmp/backend3;

    server backup1.example.com:8080   down;
    server backup2.example.com:8080   backup;
}

server {
    location / {
        proxy_pass http://upservers;  //加上http:
    }
}

配置upstream遇到的坑:
场景:做分流测试,配置从10.99.2.15上转发流量到10.99.1.49
10.99.2.15配置如下:

upstream zxn {
    server 10.99.1.49:80;
}

server{
     listen 80;
     server_name test.divide.com;
     root   /usr/local/src/klq;
     location ~ /test/ {
         proxy_set_header Host $host;
         proxy_pass http://zxn;
     }

     location ~ \.php$ {
         proxy_set_header Host $host;
         proxy_pass http://zxn;
     }
}



10.99.1.49配置如下:
 server{
       listen 80;
       server_name test.divide.com;
       access_log  logs/test.divide.com.log main;
       error_log   logs/test.divide.com.error.log error;
 
       location /test1.html {
           root   /usr/local/src/klq/;
       }
       location ~ \.php$ {
           root /usr/local/src/zhangbao;
           fastcgi_pass 127.0.0.1:9000;
           fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
           include fastcgi_params;
       }
 }

浏览器访问:test.divide.com/test/testdivide.php
echo ($__SERVER);
array(35) {
  ["HTTP_X_FORWARDED_FOR"]=>string(13) "123.125.71.45"
  ["HTTP_HOST"]=>string(15) "test.divide.com"
  ["SERVER_NAME"]=>string(15) "test.divide.com"
  ["SERVER_ADDR"]=>string(10) "10.99.1.49"
  ["REMOTE_ADDR"]=>string(10) "10.99.2.15"
  ["DOCUMENT_ROOT"]=>string(23) "/usr/local/src/zhangbao"
  ["DOCUMENT_URI"]=>string(20) "/test/testdivide.php"
  ["REQUEST_URI"]=>string(20) "/test/testdivide.php"
  ["SCRIPT_NAME"]=>string(20) "/test/testdivide.php"
  ["SCRIPT_FILENAME"]=>string(43) "/usr/local/src/zhangbao/test/testdivide.php"
  ["PHP_SELF"]=>string(20) "/test/testdivide.php"
}

结论: 1 在代理的nginx服务器中指定proxy_pass时,需要proxy_set_header $Host host;否则就算请求打到了后端upstream server, 也匹配不中对应的server
2 nginx在转发的时候,自动加上了 HTTP_X_FORWARDED_FOR字段,用于表示客户端ip
3 通过REMOTE_ADDR拿到的只是前一级代理的ip,并不能拿到真实的ip地址

指令2 proxy_next_upstream

    1  配置该指令后,网关在转发的时候如果发现后端A机器返回错误,则重新内部发起一次请求,将请求打到B机器,因此看到的日志是: 网关1条,后端2条,浏览器一条,对于用户来说是无感知的。
    但是网关的1条中,upstream_status会显示: upstream_status:500,200

指令3 hash和ip_hash

    upstream iphashtest {
        ip_hash;
        #hash user_$arg_username [consistent];
        server 127.0.0.1:8011 weight=2 max_conns=2 max_fails=2 fail_timeout=5;
        server 127.0.0.1:8012 weight=1;
    }
    其中配置了ip_hash或者是 hash,则后面的weight指令失效.

     说明:
     ip_hash:
     ip_hash的弊端就是在SNAT模式的大量Client,这些client都是统一个ip地址,最终都会被分配到同一个server。
     
     sticky:
     解决了ip_hash的弊端,实现一种基于cookie、route或者learn的session绑定,比基于ip的session更加精细。(具体如何配置参看官方文档)
     
     keepalive: 指定与后端服务器使用持久连接模式,并持久多长时间。
     通常,当upstream server为非http服务器时,例如memcache缓存服务器,可以开启该功能。让指令工作一段时间还保持连接的状态。但当后面是httpd server时,并不建议开启,会影响并发性能。

     health_check:指明对某个upstream进行健康检查,定期对上游服务器发送检测http请求。在使用healt_check时,建议关闭该location的log功能,避免不必要的日志。
     interval = time 指明发送探测间隔
     failes = number 指明失败数
     pass = number 指明通过数
     uri = uri 指明请求的资源,默认为主页面==>'/'
     match = name 指明服务器返回的状态信息,默认为2XX或3XX,也可以自定义match
     eg:
     http {
         server {
         ...
             location / {
                 proxy_pass http://backend;
                 health_check match=welcome;
             }
         }
     
         match welcome {
             status 200;
             header Content-Type = text/html;
             body ~ "Welcome to nginx!";
         }
     } 
     建议:关闭访问日志。 ngxin会阶段性的向upstream server发送访问探测,这些访问日志没有必要。

4.2.7 ngx_http_headers_module模块

基本语法:
add_header
add_trailer
expires

指令1 add_header

自定义返回给用户的response
Syntax:	add_header name value [always];
Default:	—
Context:	http, server, location, if in location

配置范例:
eg1:
server {
    listen 80;
    server_name localhost;
    add_header X-via $server_addr;  在response中显示处理该请求的服务器ip
    add_header X-Cache $upstream_cache_status;//显示是否缓存命中了,MIIS或者HIT      
    location / {
        proxy_pass http://upservers;  //加上http:
    }
}

eg2:
add_header Cache-Control private;
add_header X-First 1;

注意: 和proxy_set_header的区别,proxy_set_header是ngxin做反向代理转发请求的时候设置请求头的,而add_header是设置响应头的。

4.2.8 ngx_http_fastcgi_module

使用的是fast-cgi协议,用作处理/.php动态文件
proxy_pass:上游服务器是httpd,使用的协议是http协议
fascgi_pass:上游服务器不是httpd,使用的协议是fastcgi协议

指令集:

Directives
     fastcgi_bind
     fastcgi_buffer_size
     fastcgi_buffering
     fastcgi_buffers
     fastcgi_busy_buffers_size
     fastcgi_cache
     fastcgi_cache_background_update
     fastcgi_cache_bypass
     fastcgi_cache_key
     fastcgi_cache_lock
     fastcgi_cache_lock_age
     fastcgi_cache_lock_timeout
     fastcgi_cache_max_range_offset
     fastcgi_cache_methods
     fastcgi_cache_min_uses
     fastcgi_cache_path
     fastcgi_cache_purge
     fastcgi_cache_revalidate
     fastcgi_cache_use_stale
     fastcgi_cache_valid
     fastcgi_catch_stderr
     fastcgi_connect_timeout
     fastcgi_force_ranges
     fastcgi_hide_header
     fastcgi_ignore_client_abort
     fastcgi_ignore_headers
     fastcgi_index   :指定主页面
     fastcgi_intercept_errors
     fastcgi_keep_conn
     fastcgi_limit_rate
     fastcgi_max_temp_file_size
     fastcgi_next_upstream
     fastcgi_next_upstream_timeout
     fastcgi_next_upstream_tries
     fastcgi_no_cache
     fastcgi_param
     fastcgi_pass
     fastcgi_pass_header
     fastcgi_pass_request_body
     fastcgi_pass_request_headers
     fastcgi_read_timeout
     fastcgi_request_buffering
     fastcgi_send_lowat
     fastcgi_send_timeout
     fastcgi_split_path_info
     fastcgi_store :缓存到磁盘上
     fastcgi_store_access
     fastcgi_temp_file_write_size
     fastcgi_temp_path

使用范例

http
{ 
    ...

    fastcgi_cache_path /data/nginx/cache keys_zone=zhangbao_cache_zone:10m;
    
    map $request_method $purge_method {
        PURGE   1;
        default 0;
    }
    
    server {
        ...
        location ~ \.php$ {
            fastcgi_pass        backend;
            fastcgi_cache       zhangbao_cache_zone;
            fastcgi_cache mycache;
            fastcgi_cache 200 1d;
            fastcgi_cache 302 1h;
            fastcgi_cache any 10m;
            fastcgi_cache_use_stale error timeout http_500 http_502 http_503 http_504;    
            fastcgi_cache_key   $uri;
            fastcgi_cache_purge $purge_method;
        }
    }
}

4.2.9 ngx_http_rewrite_module模块

指令

    break
    if
    return
    rewrite
    rewrite_log
    set
用途:域名规划,向前兼容,可以将老的url全部重定向到新的url。避免了用户流量的损失,同时降低了修改的成本。   
语法:rewrite regex replacement flag
结束位:跳转完需要写上结束位      
	last -当前匹配结束之后,终止匹配,服务端会建立一个新的请求,新请求的url则是rewrite后的,那么将重新去找能匹配的location,注意虽然是建立了一个新的请求,但是新请求并不是浏览器发出的,而是nginx内部建立的,查看日志发现nginx只收到了一次请求。
	break -当前匹配结束之后即终止匹配,不会建立新的请求,也不会再去重新匹配location,而是根据rewrite后的地址去寻找对应的资源返回给客户端。   
	redirect -返回临时重定向的 HTTP 状态 302,浏览器会发送两次请求给nginx,url分别是rewrite前和rewrite后的。    
	permanent -返回永久重定向的 HTTP 状态 301 ,浏览器会记住重定向之后的url,下次在访问老url时,自动跳转到新的地址去,不再发送请求给nginx,因此就算nginx挂了都可以访问(只要能正常解析)。
eg1:rewrite ^/images/(.*\.jpg)$ /imgs/$1      
解释:^前缀匹配,&后缀匹配,&1匹配前面$括号中的内容,\转义符,将所有images/XXX.jpg的全部定向到/imgs/XXX.jpg下.      
eg2: rewrite ^/shop/(.*\.html)$  /tuangou/$1 break;   
eg3: rewrite ^/shop/(.*\.php)$   http://www.baidu.com/$1    redirect   

典型示例:


1    location{
            if ($http_user_agent ~ MSIE) {
                rewrite ^.*$ /ie.html;  
                rewrire ^(.*)$ /msie/$1;
                break; #(不break会循环重定向)
            }
            原始的url为:test.com/2..php匹配到了'/',重写之后,
            相当于把url重写成了 test.com/ie.html,去访问了ie.html 与之前的2.php没有任何关系了
    }    
        
2            if (!-e $document_root$fastcgi_script_name) {
                rewrite ^.*$ /404.html break;
             }
3 糟糕的配置
      rewrite ^/(.*)$ http://example.com/$1 permanent;
  好一点的配置
      rewrite ^ http://example.com/$request_uri
  更好的配置
      return 301 http://example.com/$request_uri
反复对比下这几个配置。 第一个 rewrite 捕获不包含第一个斜杠的完整 URI。 使用内置的变
量 $request_uri,我们可以有效的完全避免任何捕获和匹配。

4 location ~ ^/break {
    rewrite ^/break /test/ break; 
}

location ~ ^/last {
    rewrite ^/last /test/ break; 
}

location /test/ {
    default_type application/json;
    return 200 '{"status:success"}';
}


5 经典实例分析:

(1)
server {
    server_name rewrite.test.com;
    rewrite_log on;
    root html/;
    location /first {
        rewrite /first(.*) /second$1 last;
        return 200 "this is first!";
    }

    location /second {
        rewrite /second(.*) /third$1 break;
        return 200 "this is second!";
    }

    location /third {
        return 200 "this is third!";
    }
}

访问: curl rewrite.test.com/first/1.txt -x 127.0.0.1:80
          ==> 404
       curl rewrite.test.com/second/1.txt -x 127.0.0.1:80
          ==> 404
日志:2019/01/23 18:59:28 [error] 19871#0: *30 open() "/usr/local/openresty/nginx/html/third/1.txt" failed (2: No such file or directory), client: 127.0.0.1, server: rewrite.test.com, request: "GET http://rewrite.test.com/first/1.txt HTTP/1.1", host: "rewrite.test.com"
分析: /first 首先会rewrite到 /second , /second rewrite到 /third,但是由于break的作用,rewrite模块停止工作,所有的该模块的指令都失效,则nginx会找/third对应的资源/third/1.txt,没有找到则报404错误

(2)  改为如下:
server {
    server_name rewrite.test.com;
    rewrite_log on;
    root html/;
    location /first {
        rewrite /first(.*) /second$1 last;
        return 200 "this is first!";
    }

    location /second {
        rewrite /second(.*) /third$1 break;
        echo "2222";
        return 200 "this is second!";
    }

    location /third {
       echo "3333";
       return 200 "this is third!";
    }
}
访问: curl rewrite.test.com/first/1.txt -x 127.0.0.1:80
          ==> 2222
       curl rewrite.test.com/second/1.txt -x 127.0.0.1:80
          ==> 2222
分析:echo指令不是rewrite模块的,可以得到执行。      
(3) 继续改:
upstream zhangbao{
   server 10.99.2.15:80;
}
server {
    server_name rewrite.test.com;
    rewrite_log on;
    root html/;
    location /first {
        rewrite /first(.*) /second$1 last;
        return 200 "this is first!";
    }

    location /second {
        rewrite /second(.*) /third$1 break;
        proxy_pass http://zhangbao;
        proxy_set_header Host rewrite.test2.com;
        return 200 "this is second!";
    }

    location /third {
       echo "3333";
        return 200 "this is third!";
    }
}

server {
    server_name rewrite.test2.com;
    location / {
        return 200 "this is rewrite2";
    }
}

访问: curl rewrite.test.com/first/1.txt -x 127.0.0.1:80
          ==> this is rewrite2
       curl rewrite.test.com/second/1.txt -x 127.0.0.1:80
          ==> this is rewrite2

(4)继续改:
upstream zhangbao{
   server 10.99.2.15:80;
}
server {
    server_name rewrite.test.com;
    rewrite_log on;
    root html/;
    location /first {
        rewrite /first(.*) /second$1 last;
        return 200 "this is first!";
    }

    location /second {
        rewrite /second(.*) /third$1 break;
        proxy_pass http://zhangbao;
        proxy_set_header Host rewrite.test2.com;
        echo "2222";
        return 200 "this is second!";
    }

    location /third {
       echo "3333";
        return 200 "this is third!";
    }
}

server {
    server_name rewrite.test2.com;
    location / {
        return 200 "this is rewrite2";
    }
}
此时的结果为:2222
可见echo模块在upstream模块之前,先echo执行了,upstream模块没有机会执行,自然也就不会proxy_pass了
参考连接:https://www.cnblogs.com/tongxiaoda/p/7451998.html




补充说明:

1 if 之后有空格   
2 不要掉了break,不然会一直重定向。如果是IE浏览器访问,重定向到/ie.html, 则url变成xxx.com/ie.html,继续匹配location/,又进入第二个if判断,又被重定到/ie.html
3 当rewrite的正则表达时候中有“{}”时,需要将正则表达式用“”包起来,否则报错。    
Nginx使用源于perl兼容正则表达式(PCRE)库,基本语法如下:
- ^:必须以 ^ 后的实体开头
- $:必须以$前的实体结尾
- .:匹配任意字符
- []:匹配指定字符集内的任意字符,[C],[A-Z]
- {n}:重复n次
- {n,}:重复n次或更多次
- [^]:匹配不包括在指定字符集内的任意字符
- |:匹配|之前或之后的实体
- ():分组,组成一组用于匹配的实体,通常与|,$等配合使用

4.2.10 ngx_http_gzip_module模块

1 配置参数:

     gzip配置的常用参数
     gzip on|off;  #是否开启gzip
     gzip_buffers 32 4K| 16 8K #缓冲(压缩在内存中缓冲几块? 每块多大?)
     gzip_comp_level [1-9] #推荐6 压缩级别(级别越高,压的越小,越浪费CPU计算资源)
     gzip_disable #正则匹配UA 什么样的Uri不进行gzip
     gzip_min_length 200 # 开始压缩的最小长度(再小就不要压缩了,意义不在)
     gzip_http_version 1.0|1.1 # 开始压缩的http协议版本(可以不设置,目前几乎全是1.1协议)
     gzip_proxied          # 设置请求者代理服务器,该如何缓存内容
     gzip_types text/plain  application/xml # 对哪些类型的文件用压缩 如txt,xml,html ,css
     gzip_vary on|off  # 是否传输gzip压缩标志
     

4.2.11 ngx_http_memcached_module


server {
    location / {
        set            $memcached_key "$uri?$args";
        memcached_pass host:11211;
        error_page     404 502 504 = @fallback;
    }

    location @fallback {
        proxy_pass     http://backend;
    }
}


eg:
server{
      listen 80;
      server_name memcached.com;
      access_log  logs/test.com.access.log main;
      root html/test;
      location / {
          set $memcached_key $uri;
          memcached_pass 127.0.0.1:11211;
          error_page 404 callback.php;
      }
      ...
}
这里写/callback.php 和写callback.php都行

4.2.12 ngx_http_stub_status_module

       location /basic_status {
           stub_status on;
           access_log off;
       }
       
       浏览器结果显示:
       Active connections: 2 
       server accepts handled requests
        4 4 9 
       Reading: 0 Writing: 1 Waiting: 1 

4.2.13 ngx_http_stub_status_module

       location /basic_status {
           stub_status on;
           access_log off;
       }
       
       浏览器结果显示:
       Active connections: 2 
       server accepts handled requests
        4 4 9 
       Reading: 0 Writing: 1 Waiting: 1 

4.2.14 ngx_http_secure_link_module

生成安全的下载地址给用户,用户只有拿到正确的密钥和过期时间才能下载相应的资源,对服务器的资源起到了很好的保护作用。
用法实例:
可以参考官网实例

server{
    listen 80;
    server_name test.securelink.com;
    root /usr/local/mywork/test;
 
    location ~ \.(jpg|png|gif)$ {
 
        secure_link $arg_md5,$arg_expires;
        secure_link_md5 "$secure_link_expires$uri secret";
 
        if ($secure_link = "") {
            return 403;
        }
 
        if ($secure_link = "0") {
            return 410;
        }
 
    }
}

命令行得到密钥:
[root@zhangbao1 vhosts]# echo -n '2147483647/img/kb.jpg192.168.0.101 secret' | openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =
MwseFtfFdnGK0R2KfBeiyA

拼接密钥和过期时间的链接地址:
http://test.securelink.com/img/kb.jpg?md5=MwseFtfFdnGK0R2KfBeiyA&expires=2147483647
则在浏览器上输入这个网址才能下载资源

也可以用脚本实现:
生产密钥和过期时间脚本:
#!/bin/sh

servername="test.securelink.com"
download_file="/img/kb.jpg"
time_num=$(date -d "2018-10-18 00:00:00" +%s)
secure_num="zhangbao"

res=$(echo -n '${time_num}${download_file} ${secure_num}' | openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =)
echo "http://${servername}${download_file}?md5=${res}&expires=${time_num}"

执行脚本之后输出:
http://test.securelink.com/img/kb.jpg?md5=oNz7HBPflrCWeEASTeZhIw&expires=1539792000

4.2.15 ngx_http_geo_module

ngx_http_geo_module模块可以用来创建变量,其值依赖于客户端IP地址。
参考连接:http://www.ttlsa.com/nginx/using-nginx-geo-method/

4.2.16 ngx_http_geoip_module模块

模块用于定位ip地址
参考连接:https://www.centos.bz/2018/04/nginx-%E4%BD%BF%E7%94%A8-geoip-%E6%A8%A1%E5%9D%97%E5%8C%BA%E5%88%86%E7%94%A8%E6%88%B7%E5%9C%B0%E5%8C%BA/

使用方法: 
1 linux上安装Geoip库:
附件地址:链接: https://pan.baidu.com/s/1dFl1zZN 密码: x37s 
./configure 
make 
make install

2 重新编译nginx
我装的是openresty,直接在第一次安装时的编译参数后面加上geoip_module
./configure --prefix=/usr/local/openresty --add-module=/usr/local/src/openresty-1.13.6.1/bundle/ngx_cache_purge-2.3 --add-module=/usr/local/src/openresty-1.13.6.1/bundle/nginx_upstream_check_module-0.3.0 --add-module=/usr/local/src/openresty-1.13.6.1/bundle/ngx_http_consistent_hash-master --with-http_secure_link_module --with-http_geoip_module

3 配置
    geoip_country /usr/local/share/GeoIP/GeoIP.dat;
    geoip_city /usr/local/share/GeoIP/GeoLiteCity.dat;
4 使用该模块定义的变量
$geoip_country_code; – 两个字母的国家代码,如:”RU”, “US”。
$geoip_country_code3; – 三个字母的国家代码,如:”RUS”, “USA”。
$geoip_country_name; – 国家的完整名称,如:”Russian Federation”, “United States”。
$geoip_region – 地区的名称(类似于省,地区,州,行政区,联邦土地等),如:”30”。 30代码就是广州的意思
$geoip_city – 城市名称,如”Guangzhou”, “ShangHai”(如果可用)。
$geoip_postal_code – 邮政编码。
$geoip_city_continent_code。
$geoip_latitude – 所在维度。
$geoip_longitude – 所在经度。

4.2.17 ngx_http_ssl_module模块

使用方法:
一、生成CA证书    
    mkdir ssl_key
    cd ssl_key/
    openssl genrsa -idea -out zhangbao.key 1024  生成key
    
    openssl req -new -key zhangbao.key -out zhangbao.csr  生成csr文件

    openssl x509 -req -days 3650 -in zhangbao.csr -signkey zhangbao.key -out zhangbao.crt  生成crt证书文件
    
    openssl x509 -noout -text -in /usr/local/mywork/ssl_key/zhangbao.crt  查看生成的证书文件信息

二 、配置nginx
...

4.3 stream模块

4.3.1 ngx_stream_map_module

  指令:
    map
    map_hash_bucket_size
    map_hash_max_size

4.3.2 ngx_stream_split_clients_module模块

用途:创建适用于AB测试的变量
http://www.ttlsa.com/nginx/nginx-ngx_http_split_clients_module/

4.4 mail 模块

4.5 event模块

filter模块

1 sub_filter模块

用途:将返回给用户的用户的body中的内容替换掉

    location / {
        sub_filter 'Nginx.ORg' '$host/nginx';   #不区分大小写的替换
        sub_fillter 'nginx.CoM' '$host/nginx';
        sub_filter_once on;                     # 只替换一次    
        sub_filter_last_modified on;            #是否返回last_modified的header头
        sub_filter_last_modified off;
    }
    

2 addition 模块

用途: 在返回当前请求之前或者之后,通过发送子请求的方式,追加额外的响应内容
http://www.ttlsa.com/linux/nginx-modules-ngx_http_addition_module/

location / {
    add_before_body /before_action
    add_after_body   /after_action
    addition_type *;
}

location /before_action {
    return 'this is a before txt';
} 

location /after_action {
    return 'this is a after txt';
}

访问 test.com/a.txt
结果:
    this is a before txt
    a
    this is a after txt

第三方模块

1 与upstream和health_check相关

  • nginx_upsync_module + nginx_upstream_check_module(用的最多)
微博的开源项目

参考:
https://blog.csdn.net/yueguanghaidao/article/details/52801043
https://mp.weixin.qq.com/s?__biz=MzAwMDU1MTE1OQ==&mid=404151075&idx=1&sn=5f3b8c007981a2d048766f808f8c8c98&scene=2&srcid=0223XScbJrOv7noogVX6T60Q&from=timeline&isappinstalled=0#wechat_redirect
https://github.com/weibocom/nginx-upsync-module

另外每个 work 进程各自拉取、更新各自的路由表,采用这种方式的原因:一是基于 Nginx 的进程模型,彼此间数据独立、互不干扰;二是若采用共享内存,需要提前预分配,灵活性可能受限制,而且还需要读写锁,对性能可能存在潜在的影响;三是若采用共享内存,进程间协调去拉取配置,会增加它的复杂性,拉取的稳定性也会受到影响。基于这些原因,便采用了各自拉取的方式。
  • lua-resty-upstream-healthcheck
参考:https://blog.csdn.net/liutong123987/article/details/79239214
典型配置
http {
    #---------------------
    # test health check
    #---------------------
    lua_package_path "/usr/local/openresty/lualib/resty/?.lua;/usr/local/openresty/lualib/resty/upstream/?.lua;;";
     
    upstream tomcat {
        server 127.0.0.1:48080;
        server 127.0.0.1:58080;
    }
 
    lua_shared_dict healthcheck 1m;
    lua_socket_log_errors off;
    init_worker_by_lua_block {
        local hc = require "resty.upstream.healthcheck"
        local ok, err = hc.spawn_checker {
            shm = "healthcheck",
            upstream = "tomcat",
            type = "http",
            http_req = "GET /health.txt HTTP/1.0\r\nHost: tomcat\r\n\r\n",
            interval = 2000,
            timeout = 5000,
            fall = 3,
            rise = 2,
            valid_statuses = {200, 302},
            concurrency = 1,
        }
 
        if not ok then
            ngx.log(ngx.ERR, "=======> failed to spawn health checker: ", err)
            return
        end
    }
     
    server {
        listen      38080;
        server_name localhost;
     
        access_log logs/access-38080.log  main;
        error_log   logs/error-38080.log  debug;
         
        location / {
            proxy_pass   http://tomcat;
        }
                
        location /server/status {
            access_log off;
            default_type text/plain;
            content_by_lua_block {
                local hc = require "resty.upstream.healthcheck"
                ngx.say("Nginx Worker PID: ", ngx.worker.pid())
                ngx.print(hc.status_page())
            }
        }
    }
}

总结:
nginx对后端real server做健康检查有三种方法:
方法1:ngx_http_proxy_module+ngx_http_upstream_module
nginx自带的模块
方法2:nginx_upstream_check_module模块
淘宝tengine自带的模块,nginx需要手动添加
方法3:lua-resty-upstream-healthcheck模块
方法4:ngx_http_healthcheck_module模块
早期的nginx提供的健康检查模块,目前已不用

2 ngx_set_misc
如果你想对 URI 参数值中的 %XX 这样的编码序列进行解码,可以使用第三方 ngx_set_misc 模块提供的 set_unescape_uri 配置指令:

配置示例:
    location /test {  
      set_unescape_uri $name $arg_name;  
      set_unescape_uri $class $arg_class;  
      echo "name: $name";  
      echo "class: $class";  
    } 

效果:
$ curl 'http://localhost:8080/test?name=hello%20world&class=9'  
name: hello world  
class: 9

3 realip模块


几点说明

1 CDN能够记录用户端的ip,它向后端转发的时候带上两个header头:X-Forwarded-For和X-Real-IP
2 nginx通过读取这两个头能够拿到真实ip,然后将真实ip用binary_remote_addr和remote_addr变量替换掉,其值为真实ip,这样做连接限制limit_conn才有意义,这也是为什么limit_req要出现在realip模块之后

编译: --with-http_realip_module

你可能感兴趣的:(nginx)