魏长东

weichangdong

正在查看: lua 分类下的文章(第 3 页 / 共 33 篇)

Lua模式匹配

在string库中功能最强大的函数是:

string.find(字符串查找)
string.gsub(全局字符串替换)
string.gfind(全局字符串查找)
string.gmatch(返回查找到字符串的迭代器)

»»阅读全文

ngx_lua 模块

ngx_lua模块的原理:

1、每个worker(工作进程)创建一个Lua VM,worker内所有协程共享VM;
2、将Nginx I/O原语封装后注入 Lua VM,允许Lua代码直接访问;
3、每个外部请求都由一个Lua协程处理,协程之间数据隔离;
4、Lua代码调用I/O操作等异步接口时,会挂起当前协程(并保护上下文数据),而不阻塞worker;
5、I/O等异步操作完成时还原相关协程上下文数据,并继续运行;

»»阅读全文

访问有授权验证的 Redis

对于有授权验证的 redis ,正确的认证方法,请参考下面例子:

我觉得实现的方式,好棒啊。不会每次都去auth认证。

server {
    location /test {
        content_by_lua_block {
            local redis = require "resty.redis"
            local red = redis:new()

            red:set_timeout(1000) -- 1 sec

            local ok, err = red:connect("127.0.0.1", 6379)
            if not ok then
                ngx.say("failed to connect: ", err)
                return
            end

            -- 请注意这里 auth 的调用过程
            local count
            count, err = red:get_reused_times()
            if 0 == count then
                ok, err = red:auth("password")
                if not ok then
                    ngx.say("failed to auth: ", err)
                    return
                end
            elseif err then
                ngx.say("failed to get reused times: ", err)
                return
            end

            ok, err = red:set("dog", "an animal")
            if not ok then
                ngx.say("failed to set dog: ", err)
                return
            end

            ngx.say("set result: ", ok)

            -- 连接池大小是100个,并且设置最大的空闲时间是 10 秒
            local ok, err = red:set_keepalive(10000, 100)
            if not ok then
                ngx.say("failed to set keepalive: ", err)
                return
            end
        }
    }
}

»»阅读全文

lua学习之精益求精

#20160418 by wcd  演示两个请求串行和并行 串行的时间是 time=time1+time2  
并行的时间是 time=max(time1,time2);
假如两个请求耗时相同,则并行节省了一半的时间
location = /sum {
   # internal;
    content_by_lua_block {
        ngx.sleep(0.1)
        local args = ngx.req.get_uri_args()
        ngx.print(tonumber(args.a) + tonumber(args.b))
    }
}

location = /subduction {
   # internal;
    content_by_lua_block {
        ngx.sleep(0.1)
        local args = ngx.req.get_uri_args()
        ngx.print(tonumber(args.a) - tonumber(args.b))
    }
}

location = /app/test_parallels {
    content_by_lua_block {
        local start_time = ngx.now()
        local res1, res2 = ngx.location.capture_multi( {
                        {"/sum", {args={a=3, b=8}}},
                        {"/subduction", {args={a=3, b=8}}}
                    })
        ngx.say("status:", res1.status, " response:", res1.body)
        ngx.say("status:", res2.status, " response:", res2.body)
        ngx.say("time used:", ngx.now() - start_time)
    }
}

location = /app/test_queue {
    content_by_lua_block {
        local start_time = ngx.now()
        local res1 = ngx.location.capture_multi( {
                        {"/sum", {args={a=3, b=8}}}
                    })
        local res2 = ngx.location.capture_multi( {
                        {"/subduction", {args={a=3, b=8}}}
                    })
        ngx.say("status:", res1.status, " response:", res1.body)
        ngx.say("status:", res2.status, " response:", res2.body)
        ngx.say("time used:", ngx.now() - start_time)
    }
}


 location /print_param {
       content_by_lua_block {
           local arg = ngx.req.get_uri_args()
           for k,v in pairs(arg) do
               ngx.say("[GET ] key:", k, " v:", v)
           end

           ngx.req.read_body() -- 解析 body 参数之前一定要先读取 body
           local arg = ngx.req.get_post_args()
           for k,v in pairs(arg) do
               ngx.say("[POST] key:", k, " v:", v)
           end
       }
   }

      location /test_print_param {
       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)
       }
   }

»»阅读全文

lua学习之操作table

table.concat(table, sep,  start, end)

concat是concatenate(连锁, 连接)的缩写. table.concat()函数列出参数中指定table的数组部分从start位置到end位置的所有元素, 元素间以指定的分隔符(sep)隔开。除了table外, 其他的参数都不是必须的, 分隔符的默认值是空字符, start的默认值是1, end的默认值是数组部分的总长.

sep, start, end这三个参数是顺序读入的, 所以虽然它们都不是必须参数, 但如果要指定靠后的参数, 必须同时指定前面的参数.

> tbl = {"alpha", "beta", "gamma"}
> print(table.concat(tbl, ":"))
alpha:beta:gamma
> print(table.concat(tbl, nil, 1, 2))
alphabeta
> print(table.concat(tbl, "\n", 2, 3))
beta
gamma

 

但是concat 不适用于table 的key存在字符串那种 例如:wcd={wcd='123',yy='3333'} 这种。

»»阅读全文

lua学习之操作mysql

Mysql客户端

lua-resty-mysql是为基于cosocket API的ngx_lua提供的Lua Mysql客户端,通过它可以完成Mysql的操作。默认安装OpenResty时已经自带了该模块。

local function close_db(db)  
    if not db then  
        return  
    end  
    db:close()  
end  
  
local mysql = require("resty.mysql")  
--创建实例  
local db, err = mysql:new()  
if not db then  
    ngx.say("new mysql error : ", err)  
    return  
end  
--设置超时时间(毫秒)  
db:set_timeout(1000)  
  
local props = {  
    host = "127.0.0.1",  
    port = 3306,  
    database = "mysql",  
    user = "root",  
    password = "123456"  
}  
  
local res, err, errno, sqlstate = db:connect(props)  
  
if not res then  
   ngx.say("connect to mysql error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)  
   return close_db(db)  
end  
  
--删除表  
local drop_table_sql = "drop table if exists test"  
res, err, errno, sqlstate = db:query(drop_table_sql)  
if not res then  
   ngx.say("drop table error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)  
   return close_db(db)  
end  
  
--创建表  
local create_table_sql = "create table test(id int primary key auto_increment, ch varchar(100))"  
res, err, errno, sqlstate = db:query(create_table_sql)  
if not res then  
   ngx.say("create table error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)  
   return close_db(db)  
end  
  
--插入  
local insert_sql = "insert into test (ch) values('hello')"  
res, err, errno, sqlstate = db:query(insert_sql)  
if not res then  
   ngx.say("insert error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)  
   return close_db(db)  
end  
  
res, err, errno, sqlstate = db:query(insert_sql)  
  
ngx.say("insert rows : ", res.affected_rows, " , id : ", res.insert_id, "<br/>")  
  
--更新  
local update_sql = "update test set ch = 'hello2' where id =" .. res.insert_id  
res, err, errno, sqlstate = db:query(update_sql)  
if not res then  
   ngx.say("update error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)  
   return close_db(db)  
end  
  
ngx.say("update rows : ", res.affected_rows, "<br/>")  
--查询  
local select_sql = "select id, ch from test"  
res, err, errno, sqlstate = db:query(select_sql)  
if not res then  
   ngx.say("select error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)  
   return close_db(db)  
end  
  
  
for i, row in ipairs(res) do  
   for name, value in pairs(row) do  
     ngx.say("select row ", i, " : ", name, " = ", value, "<br/>")  
   end  
end  
  
ngx.say("<br/>")  
--防止sql注入  
local ch_param = ngx.req.get_uri_args()["ch"] or ''  
--使用ngx.quote_sql_str防止sql注入  
local query_sql = "select id, ch from test where ch = " .. ngx.quote_sql_str(ch_param)  
res, err, errno, sqlstate = db:query(query_sql)  
if not res then  
   ngx.say("select error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)  
   return close_db(db)  
end  
  
for i, row in ipairs(res) do  
   for name, value in pairs(row) do  
     ngx.say("select row ", i, " : ", name, " = ", value, "<br/>")  
   end  
end  
  
--删除  
local delete_sql = "delete from test"  
res, err, errno, sqlstate = db:query(delete_sql)  
if not res then  
   ngx.say("delete error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)  
   return close_db(db)  
end  
  
ngx.say("delete rows : ", res.affected_rows, "<br/>")  
  
  
close_db(db)  

»»阅读全文

lua学习之操作redis

1、基本操作

local function close_redis(red)  
    if not red then  
        return  
    end  
    local ok, err = red:close()  
    if not ok then  
        ngx.say("close redis error : ", err)  
    end  
end  
  
local redis = require("resty.redis")  
  
--创建实例  
local red = redis:new()  
--设置超时(毫秒)  
red:set_timeout(1000)  
--建立连接  
local ip = "127.0.0.1"  
local port = 6660  
local ok, err = red:connect(ip, port)  
if not ok then  
    ngx.say("connect to redis error : ", err)  
    return close_redis(red)  
end  
--调用API进行处理  
ok, err = red:set("msg", "hello world")  
if not ok then  
    ngx.say("set msg error : ", err)  
    return close_redis(red)  
end  
  
--调用API获取数据  
local resp, err = red:get("msg")  
if not resp then  
    ngx.say("get msg error : ", err)  
    return close_reedis(red)  
end  
--得到的数据为空处理  
if resp == ngx.null then  
    resp = ''  --比如默认值  
end  
ngx.say("msg : ", resp)  
  
close_redis(red) 

»»阅读全文

lua学习-进阶篇

set_by_lua 

设置nginx变量,我们用的set指令即使配合if指令也很难实现负责的赋值逻辑;

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}
 

http {
    include       mime.types;
    default_type  application/octet-stream;

    lua_package_path "lualib/?.lua;;";  #lua 模块  
    lua_package_cpath "lualib/?.so;;";  #c模块
    lua_shared_dict shared_data 1m; 
    init_by_lua_file html/init.lua; 
    #init_worker_by_lua_file html/init_work.lua; 
	lua_code_cache off;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

	map $host $wcd 
	{  
		default                     "0";  
		www.wcd.com            "wcd"; 
		www.yy.com	"yy";
	}

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location /hello {
            default_type 'text/html';  
	    
	    content_by_lua 'ngx.say("hello world")';
        }

	location /test1 {
            default_type 'text/html';  
	    
	content_by_lua_file  html/test1.lua;
        }
	location ~ /test2/(\d+)/(\d+) { 
	
	    #设置nginx变量  
	    set $a $1;   
	    set $b $host;  
	    default_type "text/html";  
	    #nginx内容处理  
	    content_by_lua_file html/test2.lua;  
	    #内容体处理完成后调用  
	    echo_after_body "ngx.var.b $b";  
	} 
	location /test3{
		
		default_type "text/html";  
		content_by_lua_file html/test3.lua; 
	}

	location /test4{
		
		default_type "text/html";  
		content_by_lua_file html/test4.lua; 
	}
	location /test5{
		
		default_type "text/html";  
		content_by_lua_file html/test5.lua; 
	}
	location /test6{
	
		default_type "text/html";  
		content_by_lua_file html/test6.lua; 
	}
	location /test7{
		default_type "text/html";  
		content_by_lua_file html/test7.lua; 
	}

	location /test8{
		default_type "text/html";  
		set_by_lua_file $num html/test8.lua;  
		 content_by_lua_file html/test8_1.lua;  
	}
	location /test9{
		default_type "text/html";  
		echo 'wcd';  
	}

	location /test10{
		default_type "text/html";  
		rewrite_by_lua_file html/test10.lua;  
		echo 'wcd';  
	}


        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

    server {
        listen       80;
        server_name  www.wcd.com;

        #charset koi8-r;
	location /{
		default_type "text/html";  
		rewrite_by_lua_file html/test10.lua;  
	}
        #access_log  logs/host.access.log  main;
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

»»阅读全文

lua学习-高级篇

Nginx Lua模块指令

Nginx共11个处理阶段,而相应的处理阶段是可以做插入式处理,即可插拔式架构;另外指令可以在http、server、server if、location、location if几个范围进行配置:

指令

所处处理阶段

使用范围

解释

init_by_lua

init_by_lua_file

loading-config

http

nginx Master进程加载配置时执行;

通常用于初始化全局配置/预加载Lua模块

init_worker_by_lua

init_worker_by_lua_file

starting-worker

http

每个Nginx Worker进程启动时调用的计时器,如果Master进程不允许则只会在init_by_lua之后调用;

通常用于定时拉取配置/数据,或者后端服务的健康检查

set_by_lua

set_by_lua_file

rewrite

server,server if,location,location if

设置nginx变量,可以实现复杂的赋值逻辑;此处是阻塞的,Lua代码要做到非常快;

rewrite_by_lua

rewrite_by_lua_file

rewrite tail

http,server,location,location if

rrewrite阶段处理,可以实现复杂的转发/重定向逻辑;

access_by_lua

access_by_lua_file

access tail

http,server,location,location if

请求访问阶段处理,用于访问控制

content_by_lua

content_by_lua_file

content

location,location if

内容处理器,接收请求处理并输出响应

header_filter_by_lua

header_filter_by_lua_file

output-header-filter

http,server,location,location if

设置header和cookie

body_filter_by_lua

body_filter_by_lua_file

output-body-filter

http,server,location,location if

对响应数据进行过滤,比如截断、替换。

log_by_lua

log_by_lua_file

log

http,server,location,location if

log阶段处理,比如记录访问量/统计平均响应时间

 

更详细的解释请参考http://wiki.nginx.org/HttpLuaModule#Directives。如上指令很多并不常用,因此我们只拿其中的一部分做演示。

»»阅读全文