基于OpenResty的web开发框架Lor

https://github.com/sumory/lor

Lor是一个运行在OpenResty上的基于Lua编写的Web框架.

  • 路由采用Sinatra风格,结构清晰,易于编码和维护.
  • API借鉴了Express的思路和设计,Node.js跨界开发者可以很快上手.
  • 支持多种路由,路由可分组,路由匹配支持正则模式.
  • 支持middleware机制,可在任意路由上挂载中间件.
  • 可作为HTTP API Server,也可用于构建传统的Web应用.

文档

http://lor.sumory.com

示例项目

快速开始

特别注意: 在使用lor之前请首先确保OpenResty已安装,并将nginx/resty命令配置到环境变量中。即在命令行直接输入nginx -vresty -v能正确执行。

一个简单示例(更复杂的示例或项目模板请使用lord命令生成):

local lor = require("lor.index")
local app = lor()

app:get("/", function(req, res, next)
    res:send("hello world!")
end)

-- 路由示例: 匹配/query/123?foo=bar
app:get("/query/:id", function(req, res, next)
    local foo = req.query.foo
    local path_id = req.params.id
    res:json({
        foo = foo,
        id = path_id
    })
end)

-- 错误处理插件,可根据需要定义多个
app:erroruse(function(err, req, res, next)
    -- err是错误对象
    ngx.log(ngx.ERR, err)
    if req:is_found() ~= true then
        return res:status(404):send("sorry, not found.")
    end
    res:status(500):send("server error")
end)

app:run()

安装

1)使用脚本安装(推荐)

使用Makefile安装lor框架:

git clone https://github.com/sumory/lor
cd lor
make install

默认lor的运行时lua文件会被安装到/usr/local/lor下, 命令行工具lord被安装在/usr/local/bin下。

如果希望自定义安装目录, 可参考如下命令自定义路径:

make install LOR_HOME=/path/to/lor LORD_BIN=/path/to/lord

执行默认安装后, lor的命令行工具lord就被安装在了/usr/local/bin下, 通过which lord查看:

$ which lord
/usr/local/bin/lord

lor的运行时包安装在了指定目录下, 可通过lord path命令查看。

2)使用opm安装

opm是OpenResty即将推出的官方包管理器,从v0.2.2开始lor支持通过opm安装:

opm install sumory/lor

注意: 目前opm不支持安装命令行工具,所以此种方式安装后不能使用lord命令。

3)使用homebrew安装

除使用以上方式安装外, Mac用户还可使用homebrew来安装lor, 该方式由@syhily提供, 更详尽的使用方法请参见这里

$ brew tap syhily/lor
$ brew install lor

至此, lor框架已经安装完毕,接下来使用lord命令行工具快速开始一个项目骨架.

使用

$ lord -h
lor ${version}, a Lua web framework based on OpenResty.

Usage: lord COMMAND [OPTIONS]

Commands:
 new [name]             Create a new application
 start                  Starts the server
 stop                   Stops the server
 restart                Restart the server
 version                Show version of lor
 help                   Show help tips

执行lord new lor_demo,则会生成一个名为lor_demo的示例项目,然后执行:

cd lor_demo
lord start

之后访问http://localhost:8888/, 即可。

更多使用方法,请参考use cases测试用例。

[openresty]第二节:操作mysql数据库

openresty操作数据库本质上调用了lua-resty-mysql 组件

具体参照git:https://github.com/openresty/lua-resty-mysql#table-of-contents

同样的在/usr/local/openresty/work/conf/ 文件夹下添加新的文件mysql.conf

内容如下:


worker_processes 1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
server {
listen 8089;
server_name localhost;
location / {
content_by_lua '
local arg = ngx.req.get_uri_args()
local mysql = require "resty.mysql"
local db, err = mysql:new()
if not db then
ngx.say("failed to instantiate mysql: ", err)
return
end

db:set_timeout(1000) -- 1 sec
local ok, err, errcode, sqlstate = db:connect{
host = "127.0.0.1",
port = 3306,
database = "test",
user = "xxxx",
password = "xxxxxxx",
max_packet_size = 1024 * 1024 }

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

--ngx.say("connected to mysql.")
local id = tonumber(arg.id)
queryStr = "select goods_id,goods_name from goods_test where goods_id ="..id
--ngx.say(queryStr)
res, err, errcode, sqlstate =
--db:query("select * from goods_test order by goods_id asc", 10)
db:query(queryStr)
if not res then
ngx.say("bad result: ", err, ": ", errcode, ": ", sqlstate, ".")
return
end
local cjson = require "cjson"
ngx.say("result: ", cjson.encode(res))
';
}

}
}

是不是很简单,然后../nginx/sbin/nginx -p `pwd`/ -s reload -c conf/mysql.conf

重新加载配置文件,这样访问localhost:8089?id=1 就可以筛选数据库中主键ID=1的数据了。应该有mysql注入问题,所以参数全部转化为int类型,基本的网络安全意识不能没有。

 

[OpenResty]Nginx之扩展Web服务器OpenResty的初步应用

官网链接:https://openresty.org/cn/getting-started.html

OpenResty (也称为 ngx_openresty)是一个全功能的 Web 应用服务器,它打包了标准的 Nginx 核心,很多的常用的第三方模块,以及它们的大多数依赖项。
OpenResty 通过汇聚各种设计精良的 Nginx 模块,从而将 Nginx 有效的变成一个强大的 Web 应用服务器,这样, Web 开发人员可以使用 Lua 脚本语言调动 Nginx 支持的各种C以及Lua 模块,快速构造出足以胜任 10K+ 并发连接响应的超高性能Web 应用系统.
OpenResty 的目标是让你的Web服务直接跑在 Nginx 服务内部,充分利用 Nginx 的非阻塞 I/O 模型,不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如MySQL,PostgreSQL,~Memcaches 以及 ~Redis 等都进行一致的高性能响应.
OpenResty 英文官网:http://openresty.org/
OpenResty 中文官网:http://openresty.org/cn/
Nginx 维基官网:http://wiki.nginx.org/
说明:
OpenResty的安装比较简单,这里要使用一个强大的功能,就是用nginx直接访问mysql,取出数据,返回给浏览器,有两种方法,第一种:使用 HttpDrizzleModule 模块,同时还需要安装 libdrizzle 1.0(在drizzle里),第二种:使用ngx_lua模块和lua库lua-resty-mysql(Mysql client Driver)。默认安装OpenResty时,还有一些lua库被安装,如
无论使用何种方法,都需要安装 pcre 库 libpcre,这是安装nginx必须的
[root@vm5 ~]# yum install pcre-devel.x86_64
方法一
1、安装 libdrizzle 1.0
[root@vm5 ~]# wget http://agentzh.org/misc/nginx/drizzle7-2011.07.21.tar.gz
[root@vm5 ~]# tar zxvf drizzle7-2011.07.21.tar.gz
[root@vm5 ~]# cd drizzle7-2011.07.21
[root@vm5 drizzle7-2011.07.21]# ./configure –without-server
[root@vm5 drizzle7-2011.07.21]# make libdrizzle-1.0
[root@vm5 drizzle7-2011.07.21]# make install-libdrizzle-1.0

2、安装 OpenResty

[root@vm5 ~]# wget http://openresty.org/download/ngx_openresty-1.2.4.14.tar.gz
[root@vm5 ~]# tar zxvf ngx_openresty-1.2.4.14.tar.gz
[root@vm5 ~]# cd ngx_openresty-1.2.4.14
[root@vm5 ngx_openresty-1.2.4.14]# ./configure –prefix=/usr/local/openresty –with-luajit –with-http_drizzle_module –with-libdrizzle=/usr/local
[root@vm5 ngx_openresty-1.2.4.14]# gmake
[root@vm5 ngx_openresty-1.2.4.14]# gmake install

3、创建测试数据

mysql> create table users(id int,username varchar(30),age tinyint);
Query OK, 0 rows affected (0.00 sec)

mysql> insert into users values(1,’zhangsan’,24);
Query OK, 1 row affected (0.00 sec)

mysql> insert into users values(2,’lisi’,26);
Query OK, 1 row affected (0.00 sec)

4、编辑 nginx.conf 配置文件

worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream mysql {
drizzle_server 127.0.0.1:3306 dbname=test user=root protocol=mysql;
}
server {
listen 80;
server_name localhost;
root html;
index index.html index.htm;
location / {
drizzle_pass mysql;
drizzle_query “select id,username,age from users where id=1”;
rds_json on;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
红色的配置用到了 HttpDrizzleModule 和 rds-json-nginx-module 模块,前一个模块是用来和数据库交互的,后面那个是做数据格式转换的,这里使用的是 json 数据格式

5、测试配置文件、启动 nginx

[root@vm5 conf]# /usr/local/openresty/nginx/sbin/nginx -t -c /usr/local/openresty/nginx/conf/nginx.conf
nginx: the configuration file /usr/local/openresty/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/openresty/nginx/conf/nginx.conf test is successful
[root@vm5 conf]# /usr/local/openresty/nginx/sbin/nginx -c /usr/local/openresty/nginx/conf/nginx.conf
[root@vm5 conf]# netstat -ntupl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local AddressForeign AddressStatePID/Program name
tcp000.0.0.0:33060.0.0.0:*LISTEN28013/mysqld
tcp000.0.0.0:800.0.0.0:*LISTEN28036/nginx.conf
tcp00:::22:::*LISTEN2901/sshd

6、测试

[root@vm5 nginx]# curl localhost
[{“id”:1,”username”:”zhangsan”,”age”:24}]

ok,效果出来了,直接用 nginx 去读 mysql 数据,而且输出的数据格式是json格式的,可用ajax折腾,是不是很牛X啊!

再来一个可以传id参数的例子:
修改 nginx 配置文件 nginx.conf
drizzle_query “select id,username,age from users where id=$arg_id”;

测试

[root@vm5 nginx]# curl localhost/?id=1
[{“id”:1,”username”:”zhangsan”,”age”:24}]
[root@vm5 nginx]# curl localhost/?id=2
[{“id”:2,”username”:”lisi”,”age”:26}]

ok,可以接收参数了,但是这么配置存在一个bug,那就是没有传递参数时会报错,这只是一个测试用例,要想在线上使用需要完善它

方法二
1、修改 nginx 配置文件 nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
root html;
index index.html index.htm;
location / {
content_by_lua ‘
local mysql = require “resty.mysql”
local db,err = mysql:new()
if not db then
ngx.say(“failed to instantiate mysql: “,err)
return
end

db:set_timeout(1000)

local ok,err,errno,sqlstate = db:connect{
host = “127.0.0.1”,
port = 3306,
database = “test”,
user = “root”,
password = “”,
max_package_size = 1024
}
if not ok then
ngx.say(“failed to connect: “, err, “: “, errno, ” “, sqlstate)
return
end

ngx.say(“connected to mysql.”)

res,err,errno,sqlstate = db:query(“select id,username,age from users where id=1”)
if not res then
ngx.say(“bad result: “, err, “: “, errno, “: “, sqlstate, “.”)
return
end

local cjson = require “cjson”
ngx.say(“result: “,cjson.encode(res))
‘;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

2、测试配置文件、重启 nginx 服务
[root@vm5 conf]# /usr/local/openresty/nginx/sbin/nginx -t -c /usr/local/openresty/nginx/conf/nginx.conf
nginx: the configuration file /usr/local/openresty/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/openresty/nginx/conf/nginx.conf test is successful
[root@vm5 conf]# killall -HUP nginx
3、测试
[root@vm5 conf]# curl localhost
connected to mysql.
result: [{“username”:”zhangsan”,”age”:24,”id”:1}]

ok,输出json格式数据了,结果也是对的。赞一个!

我们稍作修改,使其支持传递 id 参数
修改 nginx 配置文件
res,err,errno,sqlstate = db:query(“select id,username,age from users where id=”..ngx.var.arg_id)

测试配置、重启服务,略

测试结果
[root@vm5 conf]# curl localhost/?id=2
connected to mysql.
result: [{“username”:”lisi”,”age”:26,”id”:2}]
[root@vm5 conf]# curl localhost/?id=1
connected to mysql.
result: [{“username”:”zhangsan”,”age”:24,”id”:1}]

再一次ok,效果不错吧!

注意:以上代码要想用在生产环境,还需要添加一些错误捕获代码!
这里有些代码是参照官网上的,详情可以查阅官网。
未完待续…