Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save diyism/36c9d7e699cf3c67352e to your computer and use it in GitHub Desktop.
Save diyism/36c9d7e699cf3c67352e to your computer and use it in GitHub Desktop.
NginX/NginX OpenResty的内建及扩展模块的phase先后执行次序
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