自学成菜-openrestry(1)

nginx可以定义日志精选的几个变量

http://www.xxx.com/test/a?a=1&age=1

location /test {
    default_type text/html;
    echo "uri:$document_uri;args:$args;param.age=$arg_age;";
    echo "client ip:$remote_addr";
    echo "status:$status;user:$remote_user;$connection_requests";
}

output

uri:/test/a;args:a=1&age=1;param.age=1; client ip:172.17.0.1 status:200;user:;12

上面是一个很乱的输出,简单说下请求参数, <span class="katex">args是请求的参数,arg_age是后面具体的某个参数值

一些建议

有时候需要判断文件是否存在

server {
    root /var/www/example.com;
    location / {
        if (!-f $request_filename) {
            break;
        } 
    }
}

更好的写法

server {
    root /var/www/example.com;
    location / {
        try_files $uri $uri/ /index.html;
    }
}

请求 http://www.xxx.com/test/ <pre>不能识别此Latex公式: request_filename:/data/www/xxx/pay/test/ </pre>uri: /test/ try_files优先尝试是否存在<pre>不能识别此Latex公式: uri,如果不存在尝试</pre>uri/ 否则转向index.html


下面正式进入主题

hello openrestry

location /test {
    default_type text/html;

   content_by_lua '
        ngx.say("Hello Openrestry")
        ngx.say(ngx.localtime() )
   ';
}

打印字符串 返回当前时间

简单的内部调用

location = /getname {
    #此处表示属于内部调用,外部无法直接访问
    internal;

    default_type text/html;
    content_by_lua '
            local params = ngx.req.get_uri_args();
            ngx.print(params.name);
    ';
}
location = /test {
    default_type text/html;

   content_by_lua '
        local res = ngx.location.capture(
                "/getname", {args={name=ngx.var["arg_name"],age=18}}
                )

        ngx.say(ngx.var["arg_name"]);
        ngx.say("status:", res.status, " response:", res.body)

   ';
}
请求url: http://www.xxx.com/test?name=bbb 
output : bbb status:200 response:bbb

关键词: ngx.location.capture 发起请求, ngx.var["arg_name"]访问uri参数变量, ngx.say和ngx.print都属于输出数据,但ngx.say会自动在后面加\n ngx.location.capture 是非阻塞的,ngx.location.capture也可以用来完成http请求,但是它只能请求到相对于当前nginx服务器的路径,不能使用之前的绝对路径进行访问

方法1

location = /getname {

    internal;

    default_type text/html;
    content_by_lua '
            local params = ngx.req.get_uri_args();
            ngx.print(params.name);
    ';
}

方法2

location = /getage {

    internal;

    default_type text/html;
    content_by_lua '
            local params = ngx.req.get_uri_args();
            ngx.print(params.age);
    ';
}

并行调用并输出返回值

location = /test {
    default_type text/html;

   content_by_lua '
        local res1,res2 = ngx.location.capture_multi{
                {"/getage",{args="age=16&sex=1"}},
                {"/getname",{args={name=ngx.var["arg_name"]}}}
            }

        ngx.say("status:", res1.status, " response:", res1.body)
        ngx.say("status:", res2.status, " response:", res2.body)
    ';
 }

可使用ngx.sleep(0.1) 延迟测试,ngx.now()获取毫秒级时间戳,ngx.time()返回秒级别

location = /getname {
    default_type text/html;
    content_by_lua '
       ngx.say(123)
    ';
}

http重定向302跳转

location = /test {
    default_type text/html;

    rewrite_by_lua '
        return ngx.redirect("/getname")
    ';
 }

内部执行

location = /test {
    default_type text/html;

    rewrite_by_lua '
        return ngx.exec("/getname")
    ';
 }

ngx.exec 方法与 ngx.redirect 是完全不同的,前者是个纯粹的内部跳转并且 没有引入任何额外 HTTP 信号

获取请求参数

获取一个 uri 有两个方法: ngx.req.get_uri_args 、ngx.req.get_post_args

关于指令的优先级问题

location = /test {
    default_type text/html;

    content_by_lua '
        ngx.say("hello")
    ';

    rewrite_by_lua '
        ngx.say("rewirite")
    ';
    access_by_lua '
        ngx.say("access")
    ';
 }

会执行rewrite_by_lua,因为它的优先级比 其他要高

指定lua文件运行

location = /test {
    default_type text/html;

    content_by_lua_file /usr/server/openresty/nginx/conf/vhost/content.lua;
 }

content.lua

ngx.say("hello world")

其他access_by_lua_file、access_by_lua_file用法类似

init_by_lua init_by_lua_file

main.conf

init_by_lua '
    cjson = require "cjson"
';

server {
    ....
}

contnet.lua

ngx.say(cjson.encode({dog=5,cat=6}))
--output {"dog":5,"cat":6}

中断执行

ngx.exit(ngx.HTTP_OK)
ngx.exit(404)

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)

记录日志 ngx.log

ngx.log(ngx.ERR,"error!error!error!")
ngx.STDERR
ngx.EMERG
ngx.ALERT
ngx.CRIT
ngx.ERR
ngx.WARN
ngx.NOTICE
ngx.INFO
ngx.DEBUG

查看错误日志 : 2018/07/02 13:52:23 [error] 141#0: *19 [lua] content.lua:2: error!error!error! 在 Nginx 内核中硬编码限制了单条错误信息最长为 2048 字节。这个长度包含了最后的换行符和开始的时间戳。如果信息长度超过这个限制,Nginx 将把信息文本截断

ngx.ctx

这个 Lua 表可以用来存储基于请求的 Lua 环境数据,其生存周期与当前请求相同 (类似 Nginx 变量)。

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) --output : 79
     }
 }

一个简单的post内部调用

ocation = /getname {
    default_type text/html;

    content_by_lua '
        ngx.req.read_body()
        ret = ngx.req.get_body_data() --获取body体,包含post数据
        ret = cjson.decode(ret)
        ngx.say(ret.a,ret.b)
    ';
}

主程(post请求)

res = ngx.location.capture(
     '/getname',
     { method = ngx.HTTP_POST, body = '{"a":123,"b":345}' }
 )

ngx.say("status:", res.status, " response:", res.body) --输出

output : status:200 response:123345 cjson包 cjson.encode 将table转成json, cjson.decode 将json转成table

重温 : 调用

redis = {ip='127.0.0.1'}

function redis:new()
    ngx.say(self.ip)
end

redis:new()

: 调用会将自己传递赋给self

redis使用实例

local credis = require('resty.redis')

local redis = credis:new()

redis:set_timeout(1000) -- 1 sec

local ok,err = redis:connect('*****',11368)

if not ok then
    ngx.say(err)
    ngx.eof()
end

local res, err = redis:auth('123456');

if not res then
    ngx.say("failed to authenticate: ", err)
    return
end

--redis:setex('name',60,'test'); 

local res, err = redis:get("name")
    if not res then
        ngx.say("failed to get dog: ", err)
        return
    end

ngx.say(res)

- -把它放入大小为100的连接池中
-- 10秒最大空闲时间
local ok, err = red:set_keepalive(10000, 100)
if not ok then
    ngx.say("failed to set keepalive: ", err)
    return
end

-- redis:close()

setex(key,expire_time,value) https://github.com/openresty/lua-resty-redis

mysql操作

local mysql = require "resty.mysql"

local db,err = mysql:new()

if not db then 
    ngx.say('init failed mysql',err)
end

db:set_timeout(1000)

local ok,err,errcode,sqlstate = db:connect({
    host = "******",
    port = 3306,
    database = "edu_large_data",
        user = "**",
        password = "****",
        charset = "utf8",
        max_packet_size = 1024 * 1024,
})

 if not ok then
     ngx.say("failed to connect: ", err, ": ", errcode, " ", sqlstate)
    eturn
 end


res, err, errcode, sqlstate =
                    db:query("select * from flow_user_stat order by id desc limit 2")

if not res then
       ngx.say("bad result: ", err, ": ", errcode, ": ", sqlstate, ".")
       return
end

db:set_keepalive(0, 100)

ngx.say(cjson.encode(res))

[{"uv":1000,"id":4,"one_uv":80,"platform":2,"ip":700,"module":2,"pv":"1500","wait_time":"55555","ymd":20180703},{"uv":800,"id":3,"one_uv":150,"platform":1,"ip":500,"module":2,"pv":"900","wait_time":"66666","ymd":20180703}]

模拟发起远程post请求

发起请求

local res = ngx.location.capture('/getuser',{
    method = ngx.HTTP_POST,
    body = '{1,2,3}'
})

ngx.say(res.status,res.body)

因为ngx.location.capture只能访问本地,本地转发远程地址

location = /getuser {
         proxy_http_version 1.1;
         proxy_set_header Connection "";
         proxy_pass http://www.xxx.com/getpostuser;
}

模拟远程地址,只把传来值传回去

location = /getpostuser {
    content_by_lua '
        ngx.req.read_body()
          ngx.say(ngx.req.get_body_data() ) 
        ';
}

发起请求方输出 ngx.say(res.status,res.body) : 200 {1,2,3}

安装第三方拓展包

  1. 进入到 /usr/server/openresty/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
  4. local http = require "resty.http"

痛苦使用resty.http发送请求

上面已经安装了resty.http包,下面直接请求远程的接口(实际还是本机)

 local http = require "resty.http"

      local httpc = http.new()
      local res, err = httpc:request_uri("http://XXXX/getpostuser", {
        method = "POST",
        body = "a=1&b=2",
        headers = {
          ["Content-Type"] = "application/x-www-form-urlencoded",
        }
      })

      if not res then
        ngx.say("failed to request: ", err)
        return
      end

  ngx.say(res.body)

但是一直是失败的,需要配置 resolver,查看本机DNS

cat /etc/resolv.conf

resolver 192.168.65.1;

init_by_lua '
    cjson = require "cjson"
';

server {
    ...
}

再去远程请求本机访问就可以了

原文发布于微信公众号 - 呆呆熊一点通(gh_93f28f51010a)

原文发表时间:2018-07-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券