OpenResty获取uri参数

OpenResty对请求处理往往都是要需要参数的调整。如何正确获取传递参数、设置参数,就是你的必修课了。

获取uri参数

从官方文档中我们能得知获取参数的途径有两个:ngx.req.get_uri_argsngx.req.get_post_args,他们主要的区别是,前者获取的是uri上的参数,后者获取的是post请求体中的参数。

通过一个例子:

location /print_param {
    content_by_lua_block {
        local args = ngx.req.get_uri_args()
        for k, v in pairs(args) do
            ngx.say("key ", k, " value ", v)
        end

        ngx.req.read_body()
        local args = ngx.req.get_post_args()
        for k, v in pairs(args) do
            ngx.say("key ", k, " value ", v)
        end
    }
}

得到的结果是:

key b value 2&
key a value 1
key d value 4&
key c value 3

可以看到两个函数获取的参数位置是不同的。其中值得注意的是,因为nginx本身定位的原因,它是不读取请求体。所以,这里需要单独的一步去读取请求体,使用ngx.req.read_body()

传递参数

作为APTI Server的OpenResty不会满足于只读取请求体,它还能在处理的过程中改变参数。

例子:

worker_processes  1;
error_log logs/error.log info;

events {
    worker_connections 1024;
}

http {

    log_format myformat '$remote_addr $status $time_local';
    access_log logs/access.log myformat;

    server {
        listen 8080;
        charset utf-8;

        location /print_param {
            content_by_lua_block {
                local args = ngx.req.get_uri_args()
                for k, v in pairs(args) do
                    ngx.say("key ", k, " value ", v)
                end

                ngx.req.read_body()
                local args = ngx.req.get_post_args()
                for k, v in pairs(args) do
                    ngx.say("key ", k, " value ", v)
                end
            }
        }

        location /test {
            content_by_lua_block {
                local res = ngx.location.capture(
                    '/print_param',
                    {
                        method = ngx.HTTP_POST,
                        args = ngx.encode_args({a=1,b='2&'}),
                        body = ngx.encode_args({c=3,d='4&'})
                    }
                )
                ngx.say(res.body)
            }
        }
    }
}

在调用ngx.location.capture的过程中,可以传入各种参数,已满足对应业务需求。

body有时会读不到?

nginx对body的buffer是有限的,那就是说body有可能会被存入文件,这时就需要使用ngx.req.get_body_file读取请求体。

如果一定要将body放到内存中,需要设置client_body_buffer_sizeclient_max_body_size为同样的大小。参考:

http {
    server {
        listen    80;

        # 强制请求 body 到临时文件中(仅仅为了演示)
        client_body_in_file_only on;

        location /test {
            content_by_lua_block {
                function getFile(file_name)
                    local f = assert(io.open(file_name, 'r'))
                    local string = f:read("*all")
                    f:close()
                    return string
                end

                ngx.req.read_body()
                local data = ngx.req.get_body_data()
                if nil == data then
                    local file_name = ngx.req.get_body_file()
                    ngx.say(">> temp file: ", file_name)
                    if file_name then
                        data = getFile(file_name)
                    end
                end

                ngx.say("hello ", data)
            }
        }
    }
}

由于Nginx是为了解决均衡负载场景产生的,所以它默认的是不读取请求体的,根据需要获取和丢弃body对OpenResty开发至关重要。