用ngx_lua实现简单的网页编码转换网关

借助 nginx proxy 模块我们可以给 ngx_lua 很方便地实现非阻塞 HTTP 客户端功能,即使用一个被 proxy 模块处理的内部 location 作为 HTTP client stub,然后通过 ngx_lua 中的 location.capture 接口调用它访问外部 URL。当然为了能解析外部域名,还需要指定 nginx 的 resolver 地址以开启 proxy 模块的域名解析功能。

下面就是一个简单的网页编码转换网关的 nginx 配置(需要事先安装 lua-iconv 模块):

http {
    ...
    # 指定域名解析服务器地址
    resolver 127.0.0.1;
    ...
    server {
        ...
        # http client stub
        location /http_client {
            internal;
            proxy_pass $arg_url;
        }
        location /web_iconv {
            content_by_lua '
                local from, to, url = ngx.var.arg_f, ngx.var.arg_t, ngx.var.arg_u
                local capture = ngx.location.capture
                local print = ngx.print
                local iconv = require("iconv")
                local cd = iconv.new(to or "utf8", from or "gbk")
                local res = capture("/http_client?url=" .. url)
                local ostr, err = cd:iconv(res.body)
                print(ostr)
            ';
        }
        ...
    }
    ...
}

 测试一下吧:

$ curl 'http://localhost/web_iconv?f=gbk&t=utf8&u=http://www.baidu.com/'

 当然,由于 nginx proxy 模块仅支持 HTTP/1.0 协议,因此在负载很高的情况下(例如访问 REST API)效率并不高。后续我们将开发支持 HTTP/1.1 协议的代理模块,实现 keep-alive 和 pipelining 等 HTTP/1.1 高级特性,以便在 ngx_lua 中方便地进行高效率的外部 HTTP 协议访问。

Update: nginx proxy 模块在目标 url 不含路径时会默认使用父请求的路径,故在之前的例子里,如果参数 u 是 http://www.baidu.com 而不是 http://www.baidu.com/,则 proxy 模块实际去请求的 url 将是 http://www.baidu.com/web_iconv?f=gbk&t=utf8&u=http://www.baidu.com ,显然这并非我们期望的结果。因此目前如果要借用 proxy 模块作为 http client,就必须显式指明目标 url 的路径。切记!

相关推荐