一、OpenResty安装
1.下载安装包
wget https://openresty.org/download/openresty-1.11.2.5.tar.gz
2. 解压
tar -zxvf openresty-1.11.2.5.tar.gz
3. 安装
- cd openresty-1.11.2.5
- ./configure
- make
- make install
4. 配置环境变量,OpenResty默认安装在/usr/local/openresty目录下
- vi /etc/profile
- export PATH=/usr/local/openresty/nginx/sbin:$PATH
- source /etc/profile
二、hello world
修改/usr/local/openresty/nginx/conf/nginx.conf
- worker_processes 1;
-
- events {
- worker_connections 1024;
- }
-
- http {
- include mime.types;
- default_type application/octet-stream;
-
- sendfile on;
-
- server {
- listen 80;
- server_name localhost;
- location / {
- root html;
- index index.html index.htm;
- }
- location /hello {
- default_type text/html;
- content_by_lua 'ngx.say("
hello, OpenResty
")'; - }
- error_page 500 502 503 504 /50x.html;
- location = /50x.html {
- root html;
- }
- }
- }
启动nginx,访问ip/hello,可以看到如下输出,说明配置成效

三、编写lua脚本,作为输出
在ngxin目录下创建lua目录,并编写hello.lua,内容如下
ngx.say('<h1>hello,OpenResty luah1>')
修改nginx.conf中的/hello请求
- location /hello {
- default_type text/html;
- content_by_lua_file /usr/local/openresty/nginx/lua/hello.lua;
- }
请求hello返回如下,说明修改生效

四、lua操作mysql数据库 (lua-resty-mysql 的使用)
lua-resty-mysql相关操作说明
1. 创建mysql连接对象 mysql:new()
- --如果创建失败,返回nil,错误信息err
- db, err = mysql:new()
2. 建立连接 db:connect(options)
- --语法格式
- ok, err, errcode, sqlstate = db:connect(options)
- --options 必填项
- -- host:mysql地址
- -- port:mysql端口
- -- database:数据库名称
- -- user:用户名
- -- password:密码
-
-
- --options 可选项
- -- charset:编码集
- -- max_packet_size:mysql最大返回的数据大小,默认1M
- -- ssl:是否使用ssl加密,默认false
- -- pool:数据库连接池,如果不设置,默认为:user:database:host:port、user:database:path
- -- pool_size:数据库连接池大小(针对每个worker,不是整个nginx服务器)
- 如果不设置backlog,总的数据库连接不会有限制
- 如果不设置,并且backlog没有设置,则不会创建连接池
- 如果不设置,但是设置了backlog,poolsize默认为lua_socket_pool_size
- 当连接不够时,超过存活时间的连接会断开,断开后可以建立新的连接
- -- backlog:设置后可以限制总的数据库连接
3. 设置超时时间 db:set_timeout(time)
- --超时时间,单位毫秒
- db:set_timeout(time)
4. 设置空闲存活时间 db:set_keepalive(max_idle_timeout, pool_size)
- --max_idle_timeout 最大空闲时间
- --pool_size 连接池大小
- ok, err = db:set_keepalive(max_idle_timeout, pool_size)
5. 获取当前连接重复使用次数 db:get_reused_times()
- -- 如果当前连接不来自于连接池,返回0
- -- 如果当前连接来自连接池,返回一个非0值
- -- 这方法可用来判断当前连接是不是来自于连接池
- -- 如果出错,返回nil和错误信息
- times, err = db:get_reused_times()
6. 发送查询语句,不需要等待响应结果 db:send_query(sql)
- -- 如果发送成功,返回发送成功的响应数据
- -- 如果发送失败,返回nil、错误信息err
- -- 使用read_result读取响应结果
- bytes, err = db:send_query(sql)
7. 读取响应结果 db:read_result()
- -- res为查询到的结果数据,可以为一个,也可以为多个
- -- 如果出错了,结果为nil,错误信息,错误信息状态码,sql错误码
- res, err, errcode, sqlstate = db:read_result()
- -- nrows为限制结果数量
- res, err, errcode, sqlstate = db:read_result(nrows)
8. send_query 和 read_result的简化:db:query(sql)
- -- 如果出错了,结果为nil,错误信息,错误信息状态码,sql错误码
- res, err, errcode, sqlstate = db:query(sql)
- res, err, errcode, sqlstate = db:query(sql, nrows)
9. 关闭连接 db:close()
- -- 关闭成功,返回1
- ok, err = db:close()
10. 防止sql注入
因为我们nginx可以直接操作数据库,而链接中带过来的参数如果存在特殊字符,就会导致我们数据库不安全
- local name = ngx.unescape_uri(ngx.var.arg_name)
- local quoted_name = ngx.quote_sql_str(name)
- local sql = "select * from users where name = " .. quoted_name
11. 案例
创建数据库openresty,并创建表user和相关数据
- CREATE TABLE `users` (
- `id` int NOT NULL AUTO_INCREMENT,
- `username` varchar(255) DEFAULT NULL,
- `birthday` date DEFAULT NULL,
- `salary` double(10,2) DEFAULT NULL,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
-
-
- INSERT INTO `users` (`id`, `username`, `birthday`, `salary`) VALUES ('1', 'xiaowang', '1991-03-15', '9000.00');
- INSERT INTO `users` (`id`, `username`, `birthday`, `salary`) VALUES ('2', 'xiaoma', '1992-07-15', '8000.00');
编写mysql.lua
cjson 可以转json字符串
- ngx.header.content_type="application/json;charset=utf8"
- 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(10000)
-
- local ok, err, errcode, sqlstate = db:connect{
- host = "192.168.8.59",
- port = 3306,
- database = "openresty",
- user = "xxx",
- password = "xxx"
- }
- if not ok then
- ngx.say("failed to connect: ", err, ": ", errcode, " ", sqlstate)
- return
- end
- ngx.say("connected to mysql.")
- local bytes,err = db:send_query("select * from users")
- if not bytes then
- ngx.say("bad result: ", err)
- return
- end
- ngx.say("send ",bytes," bytes.")
- local res,err,errcode,sqlstate = db:read_result()
- if not res then
- ngx.say("bad result: ",err," :",errcode, ":" ,sqlstate," .")
- end
- local cjson = require 'cjson'
- for i,v in ipairs(res) do
- ngx.say(v.id..","..v.username..","..v.birthday..",".. v.salary)
- end
- ngx.say("查询数据为:",cjson.encode(res))
- db:close()
编写配置文件nginx.conf
- location = /mysql{
- content_by_lua_file /usr/local/openresty/nginx/lua/mysql.lua;
- }
访问/mysql,可以得到如下打印信息

四、lua操作redis (resty.redis的使用)
1. 创建redis对象 redis:new()
- -- 如果创建失败,返回nil,错误信息err
- red, err = redis:new()
2. 建立连接 red:connect()
- -- host ip地址
- -- port 端口号
- -- options_table 可选参数
- ok, err = red:connect(host, port, options_table?)
-
- -- optional_tables:可选参数
- -- ssl:boolean,是否使用ssl加密连接,默认false
- -- ssl_verify:是否验证ssl证书,默认false
- -- server_name: Specifies the server name for the new TLS extension
- Server Name Indication (SNI) when connecting over SSL
- -- pool:连接池名称,如果不设置,默认为host:port、unix-socket-path
- -- pool_size:连接池大小,
- 1.如果不设置,并且backlog也没有设置,连接池不会创建
- 2.如果不设置,backlog设置了,连接池大小默认为:lua_socket_pool_size
- 3.连接池最多持有pool size个连接,但不会限制总连接,可通过设置backlog限制总连接超过pool size的连接会进入队列排队,如果队列满了,则报错。
- -- backlog:超过连接池pool size的连接会进入队列排队,队列满了会报错:too many waiting connect operations
3. 设置超时时间: red:set_timeout(time)
- -- time 单位毫秒
- red:set_timeout(time)
4. 设置不同的情形的超时时间 red:set_timeouts(connect_timeout, send_timeout, read_timeout)
- -- connect_timeout 连接超时时间
- -- send_timeout 写操作超时时间
- -- read_timeout 读操作超时时间
- red:set_timeouts(connect_timeout, send_timeout, read_timeout)
5. 设置空闲存活时间
- -- max_idle_timeout 存活时间单位ms
- -- 连接池大小
- -- 会将当前连接放进连接池中
- ok, err = red:set_keepalive(max_idle_timeout, pool_size)
6. 连接重用次数
- -- 获取当前连接的重复使用次数
- -- 错误返回nil和错误信息err
- times, err = red:get_reused_times()
7. 流水线操作
- -- 初始化流水线
- red:init_pipeline()
- red:init_pipeline(n)
- -- 提交流水线
- res, err = red:commit_pipeline()
- -- 取消流水线
- red:cancel_pipeline()
8. 字符串操作
- -- 设置key-value
- -- 失败返回nil和错误信息err
- ok, err = red:set(key,value)
-
- -- 根据key获取value
- -- 失败返回nil和错误信息err
- res, err = red:get(key)
9. 权限认证
- -- 认证失败返回nil和错误信息err
- res, err = red:auth(password)
10. 案例
1. 编写redis.lua脚本文件
- ngx.header.content_type="application/json;charset=utf8"
- -- 引入 Redis
- local redis = require "resty.redis"
- --创建Redis对象
- local red = redis:new()
- --设置超时数据为3s
- red:set_timeout(3000)
- --设置redis连接信息
- local ok,err = red:connect("192.168.8.59",6379)
- --判断是否连接成功
- if not ok then
- ngx.say("failed to connection redis",err)
- return
- end
- ngx.say("connected to redis.")
- --存入 数据
- ok,err = red:set("username","TOM")
- --判断是否存入成功
- if not ok then
- ngx.say("failed to set username",err)
- return
- end
- --从 redis中获取数据
- local res,err = red:get("username")
- --将数据写会消息体中
- ngx.say(res)
- red:close()
2. nginx.conf增加/redis请求路径
- location = /redis{
- content_by_lua_file /usr/local/openresty/nginx/lua/redis.lua;
- }
3. 请求/redis

五、常用的nginx lua api
1. 获取路径占位符 /item/1001
local id = ngx.var[1]
2. 获取请求头信息
local headers = ngx.req.get_headers()
3. 获取get请求参数
- -- 返回table类型
- local args = ngx.req.get_uri_args()
- -- xx 表示url上的参数名称 ,多个同名会返回第一个的值
- -- ?xx=1&xx=2&xx=3 会返回1 ,而 get_uri_args 返回["1","2","3"]
- local xx = ngx.var.arg_xx
4. 获取请求体
- -- 读取请求体
- ngx.req.read_body()
- -- 获取表单参数,返回table类型
- local postParams = ngx.req.get_post_args()
5. 获取json参数
- -- 读取请求体
- ngx.req.read_body()
- -- 获取请求体中json参数,返回string类型
- local jsonBody = ngx.req.get_body_data()
6. 获取请求方式
- -- 获取请求方式()GET POST PUT DELETE 等
- local method,err = ngx.req.get_method();
7. 日志打印
- -- 日志级别从高到低
- -- ngx.STDERR
- -- ngx.EMERG
- -- ngx.ALERT
- -- ngx.CRIT
- -- ngx.ERR
- -- ngx.WARN
- -- ngx.NOTICE
- -- ngx.INFO
- -- ngx.DEBUG
- ngx.log(ngx.ERR,'这是日志的信息')
8. 案例
1. 编写lua脚本
- ngx.header.content_type="application/json;charset=utf8"
- local cjson = require "cjson"
-
- --请求方法
- local method = ngx.req.get_method()
- ngx.say("请求方式 : ",method)
- ngx.say("=======================")
- --请求的http协议版本
- ngx.say("http协议版本 : ",ngx.req.http_version())
- ngx.say("=======================")
-
- --get请求uri参数
- if (method == "GET") then
- ngx.say("get请求参数")
- local uri_args = ngx.req.get_uri_args()
- for k, v in pairs(uri_args) do
- ngx.say(k, ": ", v)
- end
- elseif(method == "POST") then
- ngx.req.read_body()
- local post_args = ngx.req.get_post_args()
- if post_args ~= nil then
- ngx.say("post请求参数表单方式")
- for k, v in pairs(post_args) do
- if type(v) == "table" then
- ngx.say(k, ":", table.concat(v,","))
- else
- ngx.say(k, ": ", v)
- end
- end
- end
- ngx.say("=======================")
- ngx.say("post get_body_data")
- local p_body_data = ngx.req.get_body_data()
- ngx.say(p_body_data)
- end
- ngx.say("=======================")
-
- --请求头
- local headers = ngx.req.get_headers()
- ngx.say("headers: ")
- for k,v in pairs(headers) do
- if type(v) == "table" then
- ngx.say(k, " : ", table.concat(v, ","))
- else
- ngx.say(k, " : ", v)
- end
- end
- ngx.say("=======================")
2. 配置nginx.conf
- location = /req{
- content_by_lua_file /usr/local/openresty/nginx/lua/request.lua;
- }
3. get请求

4. post请求,表单形式

5. post请求 json
六、lua_resty_kafka 集成
1. 安装kafka依赖
- #下载lua_resty_kafka ,当前目录/opt
- wget https://github.com/doujiang24/lua-resty-kafka/archive/master.zip
- #解压
- unzip master.zip
- #复制脚本文件到openresty的lualib/resty 目录下
- cp -rf /opt/lua-resty-kafka-master/lib/resty/kafka/ /usr/local/openresty/lualib/resty/
2. 编写lua脚本
- ngx.header.content_type="application/json;charset=utf8"
- local producer = require("resty.kafka.producer")
-
- -- kafka的集群信息,单机也是可以的
- local broker_list = {
- {host = "192.168.168.160", port = 9092},
- }
- -- 定义最终kafka接受到的数据是怎样的json格式
- local log_json = {}
- -- 增加read_body之后即可获取到消息体,默认情况下可能会是nil
- log_json["body"] = ngx.req.read_body()
- log_json["body_data"] = ngx.req.get_body_data()
-
- -- 定义kafka同步生产者,也可设置为异步 async
- -- 注意!!!当设置为异步时,在测试环境需要修改batch_num,默认是200条,若大不到200条kafka端接受不到消息
- -- encode()将log_json日志转换为字符串
- -- 发送日志消息,send配套之第一个参数topic:
- -- 发送日志消息,send配套之第二个参数key,用于kafka路由控制:
- -- key为nill(空)时,一段时间向同一partition写入数据
- -- 指定key,按照key的hash写入到对应的partition
-
- -- batch_num修改为1方便测试
- local bp = producer:new(broker_list, { producer_type = "async",batch_num = 1 })
- -- local bp = producer:new(broker_list)
-
- local cjson = require("cjson.safe")
- local sendMsg = cjson.encode(log_json)
- local ok, err = bp:send("lua_test",nil, sendMsg)
- if not ok then
- ngx.say("the message send error :",err)
- ngx.log(ngx.ERR, 'kafka send err:', err)
- elseif ok then
- ngx.say("the message send successful")
- else
- ngx.say("internal error ")
- end
3. 修改nginx.conf
- location = /kfk{
- content_by_lua_file /usr/local/openresty/nginx/lua/kfk.lua;
- }
4. 编写Java消费端,使用SpringBoot继承kafka
pom依赖
- <dependency>
- <groupId>org.springframework.kafkagroupId>
- <artifactId>spring-kafkaartifactId>
- dependency>
application.yml
- spring:
- kafka:
- bootstrap-servers: 192.168.168.160:9092
- consumer:
- group-id: auto-dev
listener
- @Component
- @Slf4j
- public class ConsumerListener {
- @KafkaListener(topics = {"lua_test"})
- public void onMessage(ConsumerRecord
record) { - log.info("【topic】 {} 【消息】{}",record.topic(), record.value());
- }
- }
3. 测试结果
发送请求

消费者消费消息

七、nginx的相关命令
- #到nginx目录下,使用默认配置文件启动
- ./sbin/ngxin
- #启动时指定配置文件
- ./sbin/ngxin -c /opt/nginx/nginx.conf
- #设置前缀路径
- ./sbin/ngxin -p /home/www
- #重启Nginx
- nginx -s reopen
- #程序加载配置文件(nginx.conf),然后以优雅的方式重启Nginx。
- nginx -s reload
- #强制停止Nginx服务
- nginx -s stop
- #优雅的停止Nginx服务
- nginx -s quit
八、总结
OpenResty是个利器,大家好好把握!哈哈哈