NginX OpenResty的内建及扩展模块的phase先后执行次序
kevin.Zhu 发布于:2022-3-30 16:46 分类:文摘 有 11 人浏览,获得评论 0 条
https://gist.github.com/fannheyward/39495ede697f423c3d7a
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"';