Openresty 执行阶段与api之间的关系(一)

                                                Openresty与nginx的 执行阶段

常见的七个阶段的顺序:

set_by_lua
rewrite_by_lua
access_by_lua
content_by_lua
header_filter_by_lua
body_filter_by_lua
log_by_lua

每个阶段的作用:

set_by_lua: 流程分支处理判断变量初始化
rewrite_by_lua: 转发、重定向、缓存等功能(例如特定请求代理到外网)
access_by_lua: IP准入、接口权限等情况集中处理(例如配合iptable完成简单防火墙)
content_by_lua: 内容生成
header_filter_by_lua: 应答HTTP过滤处理(例如添加头部信息)
body_filter_by_lua: 应答BODY过滤处理(例如完成应答内容统一成大写)
log_by_lua: 会话完成后本地异步完成日志记录(日志可以记录在本地,还可以同步到其他机器)

知道这几个阶段之后,如何利用Nginx的函数变量去构建自己想要的系统,了解nginx变量和函数的作用域也是十分关键。

nginx的变量函数的阶段作用域:

ngx.arg

例子: val = ngx.arg[index]

作用域: set_by_lua*, body_filter_by_lua*

set_by_lua 
         'return tonumber(ngx.arg[1]) + tonumber(ngx.arg[2])';
         

ngx.var.VARIABLE

例子: ngx.var.VAR_NAME

作用域: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*

set $my_var '';
     content_by_lua_* {
         ngx.var.my_var = 123;
   
     }

HTTP method constants

作用域:init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*

  ngx.HTTP_GET
  ngx.HTTP_HEAD
  ngx.HTTP_PUT
  ngx.HTTP_POST
  ngx.HTTP_DELETE
  ngx.HTTP_OPTIONS   (added in the v0.5.0rc24 release)
  ngx.HTTP_MKCOL     (added in the v0.8.2 release)
  ngx.HTTP_COPY      (added in the v0.8.2 release)
  ngx.HTTP_MOVE      (added in the v0.8.2 release)
  ngx.HTTP_PROPFIND  (added in the v0.8.2 release)
  ngx.HTTP_PROPPATCH (added in the v0.8.2 release)
  ngx.HTTP_LOCK      (added in the v0.8.2 release)
  ngx.HTTP_UNLOCK    (added in the v0.8.2 release)
  ngx.HTTP_PATCH     (added in the v0.8.2 release)
  ngx.HTTP_TRACE     (added in the v0.8.2 release)

HTTP status constants

作用域: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*

value = ngx.HTTP_CONTINUE (100) (first added in the v0.9.20 release)
   value = ngx.HTTP_SWITCHING_PROTOCOLS (101) (first added in the v0.9.20 release)
   value = ngx.HTTP_OK (200)
   value = ngx.HTTP_CREATED (201)
   value = ngx.HTTP_ACCEPTED (202) (first added in the v0.9.20 release)
   value = ngx.HTTP_NO_CONTENT (204) (first added in the v0.9.20 release)
   value = ngx.HTTP_PARTIAL_CONTENT (206) (first added in the v0.9.20 release)
   value = ngx.HTTP_SPECIAL_RESPONSE (300)
   value = ngx.HTTP_MOVED_PERMANENTLY (301)
   value = ngx.HTTP_MOVED_TEMPORARILY (302)
   value = ngx.HTTP_SEE_OTHER (303)
   value = ngx.HTTP_NOT_MODIFIED (304)
   value = ngx.HTTP_TEMPORARY_REDIRECT (307) (first added in the v0.9.20 release)
   value = ngx.HTTP_BAD_REQUEST (400)
   value = ngx.HTTP_UNAUTHORIZED (401)
   value = ngx.HTTP_PAYMENT_REQUIRED (402) (first added in the v0.9.20 release)
   value = ngx.HTTP_FORBIDDEN (403)
   value = ngx.HTTP_NOT_FOUND (404)
   value = ngx.HTTP_NOT_ALLOWED (405)
   value = ngx.HTTP_NOT_ACCEPTABLE (406) (first added in the v0.9.20 release)
   value = ngx.HTTP_REQUEST_TIMEOUT (408) (first added in the v0.9.20 release)
   value = ngx.HTTP_CONFLICT (409) (first added in the v0.9.20 release)
   value = ngx.HTTP_GONE (410)
   value = ngx.HTTP_UPGRADE_REQUIRED (426) (first added in the v0.9.20 release)
   value = ngx.HTTP_TOO_MANY_REQUESTS (429) (first added in the v0.9.20 release)
   value = ngx.HTTP_CLOSE (444) (first added in the v0.9.20 release)
   value = ngx.HTTP_ILLEGAL (451) (first added in the v0.9.20 release)
   value = ngx.HTTP_INTERNAL_SERVER_ERROR (500)
   value = ngx.HTTP_METHOD_NOT_IMPLEMENTED (501)
   value = ngx.HTTP_BAD_GATEWAY (502) (first added in the v0.9.20 release)
   value = ngx.HTTP_SERVICE_UNAVAILABLE (503)
   value = ngx.HTTP_GATEWAY_TIMEOUT (504) (first added in the v0.3.1rc38 release)
   value = ngx.HTTP_VERSION_NOT_SUPPORTED (505) (first added in the v0.9.20 release)
   value = ngx.HTTP_INSUFFICIENT_STORAGE (507) (first added in the v0.9.20 release)

 

Nginx log level constants

作用域: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*

ngx.STDERR
   ngx.EMERG
   ngx.ALERT
   ngx.CRIT
   ngx.ERR
   ngx.WARN
   ngx.NOTICE
   ngx.INFO
   ngx.DEBUG

print

例子: print(...)

作用域: init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*

ngx.ctx

注意和ngx.var.VARIABLE的区别,这个是一个完整请求的作用范围,一个是某个请求阶段的作用范围。

作用域: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*

location /test {
     rewrite_by_lua_block {
         ngx.ctx.foo = 76
     }
     access_by_lua_block {
         ngx.ctx.foo = ngx.ctx.foo + 3
     }
     content_by_lua_block {
         ngx.say(ngx.ctx.foo)
     }
 }

不过要注意几种使用情况:有子请求的情况下,请求中执行另一个请求的情况下:作用范围不适用eg:

 location /sub {
     content_by_lua_block {
         ngx.say("sub pre: ", ngx.ctx.blah)
         ngx.ctx.blah = 32
         ngx.say("sub post: ", ngx.ctx.blah)
     }
 }

 location /main {
     content_by_lua_block {
         ngx.ctx.blah = 73
         ngx.say("main pre: ", ngx.ctx.blah)
         local res = ngx.location.capture("/sub")
         ngx.print(res.body)
         ngx.say("main post: ", ngx.ctx.blah)
     }
 }
Then GET /main will give the output

 main pre: 73
 sub pre: nil
 sub post: 32
 main post: 73

-----------------------------------------------
location /new {
     content_by_lua_block {
         ngx.say(ngx.ctx.foo)
     }
 }

 location /orig {
     content_by_lua_block {
         ngx.ctx.foo = "hello"
         ngx.exec("/new")
     }
 }
Then GET /orig will give

 nil

ngx.location.capture

例子: res = ngx.location.capture(uri, options?)

作用域: rewrite_by_lua*, access_by_lua*, content_by_lua*

在一个location中执行子请求的时候,是非阻塞的,这个特性非常关键,你以location划分功能,再组合。

ngx.location.capture_multi(混合子请求,同上)

例子: res1, res2, ... = ngx.location.capture_multi({ {uri, options?}, {uri, options?}, ... })

作用域: rewrite_by_lua*, access_by_lua*, content_by_lua*

ngx.header.HEADER

例子: ngx.header.HEADER = VALUE

例子: value = ngx.header.HEADER

作用域: rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*

-- equivalent to ngx.header["Content-Type"] = 'text/plain'
 ngx.header.content_type = 'text/plain';

 ngx.header["X-My-Header"] = 'blah blah';

Multi-value headers can be set this way:

ngx.header['Set-Cookie'] = {'a=32; path=/', 'b=4; path=/'}

ngx.req.get_method

例子: method_name = ngx.req.get_method()

作用域: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, balancer_by_lua*

ngx.req.set_uri

syntax: ngx.req.set_uri(uri, jump?)

context: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*

ngx.req.get_uri_args

例子: args = ngx.req.get_uri_args(max_args?)

作用域: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, balancer_by_lua*

Returns a Lua table holding all the current request URL query arguments.

location = /test {
     content_by_lua_block {
         local args = ngx.req.get_uri_args()
         for key, val in pairs(args) do
             if type(val) == "table" then
                 ngx.say(key, ": ", table.concat(val, ", "))
             else
                 ngx.say(key, ": ", val)
             end
         end
     }
 }

ngx.req.socket

syntax: tcpsock, err = ngx.req.socket()

syntax: tcpsock, err = ngx.req.socket(raw)

context: rewrite_by_lua*, access_by_lua*, content_by_lua*

这个socket是nginx中非阻塞的socket,作用范围很明显,但只要掌握一定技巧使用还是可以越过作用范围的。

https://github.com/cloudflare/lua-resty-logger-socket 作者跳过作用域的一个作品,通过的nginx.time.at(点到为止,有兴趣的同学可以看看源码)

ngx.exec

syntax: ngx.exec(uri, args?)

context: rewrite_by_lua*, access_by_lua*, content_by_lua*

ngx.exec('/some-location');
 ngx.exec('/some-location', 'a=3&b=5&c=6');
 ngx.exec('/some-location?a=3&b=5', 'c=6');

ngx.print

syntax: ok, err = ngx.print(...)

context: rewrite_by_lua*, access_by_lua*, content_by_lua*

Emits arguments concatenated to the HTTP client (as response body). If response headers have not been sent, this function will send headers out first and then output body data.

local table = {
     "hello, ",
     {"world: ", true, " or ", false,
         {": ", nil}}
 }
 ngx.print(table)

ngx.sleep

syntax: ngx.sleep(seconds)

context: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*

ngx.escape_uri

syntax: newstr = ngx.escape_uri(str)

context: init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*

ngx.unescape_uri

syntax: newstr = ngx.unescape_uri(str)

context: init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*

ngx.say(ngx.unescape_uri("b%20r56+7"))

gives the output

b r56 7

ngx.encode_args

syntax: str = ngx.encode_args(table)

context: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*

ngx.encode_args({foo = 3, ["b r"] = "hello world"})

yields

foo=3&b%20r=hello%20world

Multi-value query args are also supported. Just use a Lua table for the argument's value, for example:

ngx.encode_args({baz = {32, "hello"}})

gives

baz=32&baz=hello

ngx.decode_args

syntax: table = ngx.decode_args(str, max_args?)

context: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*

ngx.encode_base64

syntax: newstr = ngx.encode_base64(str, no_padding?)

context: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*

ngx.decode_base64

syntax: newstr = ngx.decode_base64(str)

context: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*

ngx.md5

syntax: digest = ngx.md5(str)

context: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*

location = /md5 { content_by_lua_block { ngx.say(ngx.md5("hello")) } }

yields the output

5d41402abc4b2a76b9719d911017c592

ngx.is_subrequest

syntax: value = ngx.is_subrequest

context: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*

Returns true if the current request is an nginx subrequest, or false otherwise.

ngx.re.match

syntax: captures, err = ngx.re.match(subject, regex, options?, ctx?, res_table?)

context: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*

ngx.re.find

syntax: from, to, err = ngx.re.find(subject, regex, options?, ctx?, nth?)

context: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*

ngx.shared.DICT

syntax: dict = ngx.shared.DICT

syntax: dict = ngx.shared[name_var]

context: init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*

Fetching the shm-based Lua dictionary object for the shared memory zone named DICT defined by thelua_shared_dict directive.

Shared memory zones are always shared by all the nginx worker processes in the current nginx server instance.

The resulting object dict has the following methods:

getget_stalesetsafe_setaddsafe_addreplacedeleteincrlpushrpushlpoprpop

llenflush_allflush_expiredget_keys

Here is an example:

http {
     lua_shared_dict dogs 10m;
     server {
         location /set {
             content_by_lua_block {
                 local dogs = ngx.shared.dogs
                 dogs:set("Jim", 8)
                 ngx.say("STORED")
             }
         }
         location /get {
             content_by_lua_block {
                 local dogs = ngx.shared.dogs
                 ngx.say(dogs:get("Jim"))
             }
         }
     }
 }

Let us test it:

$ curl localhost/set
 STORED

 $ curl localhost/get
 8

 $ curl localhost/get
 8

ngx.socket.udp(想要二次开发很关键的函数)

syntax: udpsock = ngx.socket.udp()

context: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*

Creates and returns a UDP or datagram-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object:

It is intended to be compatible with the UDP API of the LuaSocket library but is 100% nonblocking out of the box.

ngx.socket.tcp(想要二次开发很关键的函数)

syntax: tcpsock = ngx.socket.tcp()

context: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*

Creates and returns a TCP or stream-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object:

It is intended to be compatible with the TCP API of the LuaSocket library but is 100% nonblocking out of the box. Also, we introduce some new APIs to provide more functionalities.

The cosocket object created by this API function has exactly the same lifetime as the Lua handler creating it. So never pass the cosocket object to any other Lua handler (including ngx.timer callback functions) and never share the cosocket object between different NGINX requests.

For every cosocket object's underlying connection, if you do not explicitly close it (via close) or put it back to the connection pool (via setkeepalive), then it is automatically closed when one of the following two events happens:

  • the current request handler completes, or
  • the Lua cosocket object value gets collected by the Lua GC.

Fatal errors in cosocket operations always automatically close the current connection (note that, read timeout error is the only error that is not fatal), and if you call close on a closed connection, you will get the "closed" error.

Starting from the 0.9.9 release, the cosocket object here is full-duplex, that is, a reader "light thread" and a writer "light thread" can operate on a single cosocket object simultaneously (both "light threads" must belong to the same Lua handler though, see reasons above). But you cannot have two "light threads" both reading (or writing or connecting) the same cosocket, otherwise you might get an error like "socket busy reading" when calling the methods of the cosocket object.

转载于:https://my.oschina.net/QAAQ/blog/775187

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值