在lua中操作http请求有两种方式

第一种方式:使用通过ngx.location.capture 去方式实现,但是有一些限制

第二种方式:因为openresty默认没有引入第三方http 客户端类库lua-resty-http,需要下载。

下载lua-resty-http类库

  1. cd /usr/example/lualib/resty/  
  2. wget https://raw.githubusercontent.com/pintsized/lua-resty-http/master/lib/resty/http_headers.lua  
  3. wget https://raw.githubusercontent.com/pintsized/lua-resty-http/master/lib/resty/http.lua  
#测试http发送请求
        location = /testHttp {

                content_by_lua_block{
                        local http = require("resty.http")
                        --创建http客户端实例
                        local httpc = http:new()

                        local resp,err = httpc:request_uri("http://issm.suning.com",
                        {
                                method = "GET",
                                path="/productDetail_P11271.htm",
                                headers = {["User-Agent"]="Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111 Safari/537.36"}
                        })
                        if not resp then
                                ngx.say("request error:",err)
                                return
                        end
                        --获取状态码
                        ngx.status = resp.status

                        --获取响应信息
                        --响应头中的Transfer-Encoding和Connection可以忽略,因为这个数据是当前server输出的。
                        for k,v in pairs(resp.headers) do
                                if k ~= "Transfer-Encoding" and k ~= "Connection" then
                                        ngx.header[k] =v
                                end
                        end

                        --响应体
                        ngx.say(resp.body)

                        httpc:close()

                }

        }

执行 出现如下结果:

lua 调用JavaScript lua 调用http_lua 调用JavaScript

注意:需要在http模块中添加如下指令来做DNS解析,不然会报出解析域名错误

          resolver 8.8.8.8;  

   其http客户端也支持连接池,与redis、mysql连接池配置一致。

 

ngx.location.capture

ngx.location.capture也可以用来完成http请求,但是它只能请求到相对于当前nginx服务器的路径,不能使用之前的绝对路径进行访问,但是我们可以配合nginx upstream实现我们想要的功能。

1、在nginx.cong中的http部分添加如下upstream配置

Java代码  

  1. upstream backend {  
  2.     server s.taobao.com;  
  3. 100;  
  4. }  

即我们将请求upstream到backend;另外记得一定要添加之前的DNS解析器。

 

2、在example.conf配置如下location

Java代码  

  1. location ~ /proxy/(.*) {  
  2.    internal;  
  3. //backend/$1$is_args$args;
  4. }  

internal表示只能内部访问,即外部无法通过url访问进来; 并通过proxy_pass将请求转发到upstream。

 3、test_http_2.lua

Java代码  

local resp = ngx.location.capture("/proxy/search", {  
    method = ngx.HTTP_GET,  
    args = {q = "hello"}  
  
})  
if not resp then  
    ngx.say("request error :", err)  
    return  
end  
ngx.log(ngx.ERR, tostring(resp.status))  
  
--获取状态码  
ngx.status = resp.status  
  
--获取响应头  
for k, v in pairs(resp.header) do  
    if k ~= "Transfer-Encoding" and k ~= "Connection" then  
        ngx.header[k] = v  
    end  
end  
--响应体  
if resp.body then  
    ngx.say(resp.body)  
end

通过ngx.location.capture发送一个子请求,此处因为是子请求,所有请求头继承自当前请求,还有如ngx.ctx和ngx.var是否继承可以参考官方文档http://wiki.nginx.org/HttpLuaModule#ngx.location.capture。 另外还提供了ngx.location.capture_multi用于并发发出多个请求,这样总的响应时间是最慢的一个,批量调用时有用。

 

 4、访问如http://192.168.1.2/lua_http_2进行测试可以看到淘宝搜索界面。

 我们通过upstream+ngx.location.capture方式虽然麻烦点,但是得到更好的性能和upstream的连接池、负载均衡、故障转移、proxy cache等特性。

 不过因为继承在当前请求的请求头,所以可能会存在一些问题,比较常见的就是gzip压缩问题,ngx.location.capture不会解压缩后端服务器的GZIP内容,解决办法可以参考https://github.com/openresty/lua-nginx-module/issues/12;因为我们大部分这种http调用的都是内部服务,因此完全可以在proxy location中添加proxy_pass_request_headers off;来不传递请求头。