Last active
August 2, 2017 01:03
-
-
Save diyism/36c9d7e699cf3c67352e to your computer and use it in GitHub Desktop.
NginX/NginX OpenResty的内建及扩展模块的phase先后执行次序
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
NginX/NginX OpenResty的内建及扩展模块的phase先后执行次序: | |
参考: http://wiki.nginx.org/Phases | |
http://blog.sina.com.cn/openresty | |
需要关注的phase有: | |
-1:http config: | |
在/usr/local/openresty/nginx/conf/nginx.conf的http段落有可以载入lua的共用函数, 比如: | |
init_by_lua_file /var/workspace/www/violation_nginx/lf; | |
0.server selection: server(listen, server_name) | |
匹配listen端口和server_name | |
1.server rewrite: set, rewrite, return, set_by_lua | |
2.server rewrite tail: more_set_input_headers, rewrite_by_lua | |
即使是server阶段的rewrite也会重新从server selection再进来一次 | |
3.server access: allow, deny | |
4.server access tail: access_by_lua | |
server access就是一次过不会像rewrite一样重新进来 | |
5.server try files: try_files | |
6.location selection: location | |
选择处理匹配的url, 该phase无第三方模块插入 | |
prefix strings之间遵循"最长子串匹配原则", prefix的意思是从url首部匹配起 | |
regular expressions之间遵循"先定义优先匹配原则", regex是匹配整个url的规则 | |
优先次序: stop regex prefix string(^~)>regular expression>prefix string | |
location = {exact_url} | |
location ^~ {prefix_string_if_any} | |
location ~ {case_sensitive_regular_expression} | |
location ~* {case_insensitive_regular_expression} | |
location {prefix_string_if_no_RE_match} #这个不太严格, /shanghaikkk 的请求也会进入 /shanghai 的location代码内 | |
if (-f和!-f) 判断是否存在location或文件 | |
if (-d和!-d) 判断是否存在location或目录 | |
if (-e和!-e) 判断是否存在location或文件或目录 | |
if (-x和!-x) 判断文件是否可执行 | |
if ($a = $b 和 $a != $b) | |
if ($a ~ $b 和 $a !~ $b) | |
if ($a ~* $b 和 $a !~* $b) | |
location / | |
{ | |
#"location if"导致其所在location比"server rewrite"都先执行, 破坏了官方文档里server比location早的次序(这才是if is evil的真正原因), 所以改为try_files | |
#if (!-e $request_filename){ | |
# rewrite ^/(.*)$ /index.php/$1 last; | |
#} | |
try_files $uri $uri/ /index.php$uri; | |
index index.php index.html index.htm; # rewrite阶段在index的content阶段前面 | |
} | |
其中ngx.var.request_filename==ngx.var.document_root..ngx.var.uri, 奇怪的是if -e $request_filename首先检查的是location且能匹配上 | |
调试location匹配分支, 不要用echo, content_by_lua因为会晚于rewrite, return, access, try files等命令, 用rewrite_by_lua或直接用return: | |
return 200 'hello'; | |
如果要用echo等可加break(但只屏蔽同段落之后部份, 但若在server段,http段定义access是继承到每个location rewrite之后就执行, 比echo提前): | |
echo 'jack'; break; | |
7.location rewrite: set, rewrite, return, set_by_lua | |
set, set_by_lua同处location rewrite阶段且可以混合运行 | |
rewrite直接发起内部重定向, 改写$document_uri(ngx.var.document_uri)等同$uri(ngx.var.uri), 不动原始请求:$request_uri(ngx.var.request_uri), 这个含参数, 前两个不含GET参数, | |
并跳回location selection阶段重新执行, 跳转后$request_uri仍不改变, 所以php里面的route用的是原始请求比如"/help_lua/write_file"而不是"/index.php/help_lua/write_file" | |
实现http里的location redirect应该用openresty的第9 phase里的more_set_headers或: return 301 https://mydomain/newurl; 或: ngx.redirect | |
而proxy_pass是进行代理请求, 直接返回内容, | |
而proxy_redirect的意思则是把response header里的location进行替换, 一般跟在proxy_pass后面. | |
根据系统的环境变量设置参数: | |
set_by_lua $ENVIROMENT 'return os.getenv("ENVIROMENT")'; | |
但只有proxy_pass等少数命令支持变量, 像memcached_pass等命令不支持(memcache服务器ip还可以通过设本地host实现, port则无法根据环境变化: memcached_pass memcache_server:11215;) | |
8.location rewrite tail: more_set_input_headers, rewrite_by_lua | |
more_set_input_headers可以改写header, rewrite_by_lua在location rewrite tail阶段执行代码 | |
rewrite_by_lua内ngx.req.set_uri("/foo", true);相当于location rewrite步骤的rewrite ^ /foo last; 注意rewrite_by_lua内ngx.req.set_uri实际是必须带第二参数的, 也就是rewrite last | |
rewrite_by_lua内ngx.req.set_uri_args("a=3");ngx.req.set_uri("/foo", true);相当于rewrite ^ /foo?a=3? last; | |
rewrite_by_lua内return ngx.exec('/foo?a=3');相当于rewrite ^ /foo?a=3? last; 由于ngx.exec不会主动返回, 所以一般前面都加"return " | |
rewrite_by_lua内ngx.req.set_uri(ngx.re.sub(ngx.var.uri, "^/test/(.*)", "$1", "o"), false);相当于rewrite ^/test/(.*) /$1 break; | |
为避免死循环(11次rewrite后系统报500错误)可以加上ngx.req.set_header("city_2_api", "1")来设标志, 加上ngx.req.get_headers()["city_2_api"]来取标志, | |
当然也可直接set $city_2_api 0;然后ngx.var.city_2_api=1; | |
跳转后nginx里还要用$request_uri的地方可以改用自己set的$updated_request_uri, | |
而fastcgi_pass到php-fpm的location内也可以加上fastcgi_param REQUEST_URI $updated_request_uri; 当然server内第一步就要set $updated_request_uri $request_uri; | |
9.access: allow, deny | |
deny相当于ngx.exit(403), allow/deny后参数可以是IP, IP/mask(16,24等), all | |
10.access tail: access_by_lua | |
access_by_lua在access tail阶段执行代码 | |
access_by_lua不会运行于ngx.location.capture内 | |
access_by_lua内有ngx.say输出则content阶段不会被执行到 | |
11.try files: try_files | |
try_files最后一个参数之前的参数是正常的在检查file/folder存在, 存在则改写$uri内置参数(然后交给下面content输出模块或index模块或static模块处理), | |
最后一个参数不检查文件存在而直接internal redirect | |
12.content: echo, proxy_pass, fastcgi_pass, content_by_lua | |
多个echo和一个content_by_lua同处content phase, | |
但ngx_proxy, ngx_echo, ngx_lua多个content模块不是混合运行而是独立运行的, | |
排在后面的模块覆盖content的值, ngx_echo模块启动以第一个echo为准. | |
对"/"结尾的location且没有上面content输出模块启动才触发index, 类似try_files检查多个文件名是否存在而不是直接重定向, 存在则内部重定向, 都不存在则执行autoindex模块, 如果最后参数是"/..."则直接internel redirect | |
对"/"结尾的location且没有上面content模块启动, autoindex=on, 则找不到index时list目录, 如果off(默认)则自动ngx.exit(404); 未找到 | |
ngx_index模块找到文件内部重定向后将由ngx_static来输出这个找到的文件, 既没有content输出,也没有nginx_index,则ngx_static把url location映射位置的文件输出 | |
跟fastcgi_pass一起的还有fastcgi_index, fastcgi_param, include指令: | |
"include fastcgi_params;", include可以在各个级别, 这里就是包含"/etc/nginx/"(include的根目录, openresty是/usr/local/openresty/nginx, 用"nginx -V"看prefix)内的fastcgi_params文件, 里面有很多fastcgi_param定义指令 | |
ngx.location.capture并不重新指定fastcgi_params里用到的$fastcgi_script_name, $request_uri, $remote_addr这几个nginx变量, 而是直接继承调用它的那个request里的环境 | |
13.output header filter: more_set_headers | |
输出header, 如more_set_headers 'Content-Type: text/html'; 配置return 200 'hello'; 这里无法用echo, 因return在rewrite phase比echo的content phase早 | |
9和10默认NginX未安装, NginX OpenResty带有 | |
14.output filter: echo_before_body, echo_after_body, body_filter_by_lua | |
最后的output filter phase用来修改content的值 | |
body_filter_by_lua如果改变内容长度得把content_length header先移除: | |
header_filter_by_lua 'ngx.header.content_length = nil'; | |
body_filter_by_lua 'ngx.arg[1] = string.upper(ngx.arg[1]).."end of the file"'; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment