用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 的路径。切记!