🍓 简介:java系列技术分享(👉持续更新中…🔥)
🍓 初衷:一起学习、一起进步、坚持不懈
🍓 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正🙏
🍓 希望这篇文章对你有所帮助,欢迎点赞 👍 收藏 ⭐留言 📝🍓 更多文章请点击
文章目录
- 一、OpenResty简介
- 二、OpenResty安装
- 2.1 安装开发库
- 2.2 安装OpenResty仓库
- 2.3 安装OpenResty
- 2,4 安装opm工具
- 2.5 目录结构
- 2.6 配置nginx的环境变量
- 2.7 启动和运行
- 三、使用步骤
- 3.1 添加对OpenResty的Lua模块的加载
- 3.2 OpenResty监听请求
- 3.3 编写item.lua
- 3.4 重新加载配置
- 四、请求参数处理
- 4.1 获取参数的API
- 4.2 获取参数并返回
- 五、发送http请求的API
- 5.1 封装http工具
- 六、cjson的模块用来处理JSON的序列化和反序列化
- 七、OpenResty提供了操作Redis的模块
- 7.1 封装Redis工具
- 7.2 实现Redis查询
- 八、Nginx本地缓存
- 8.1 本地缓存API
- 8.2 实现本地缓存查询
一、OpenResty简介
官网地址
: http://openresty.org/cn/
OpenResty® 是一个
基于 Nginx
的高性能 Web 平台,用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。
具备下列特点:
- 具备Nginx的完整功能
- 基于Lua语言进行扩展,集成了大量精良的 Lua 库、第三方模块
- 允许使用Lua自定义业务逻辑、自定义库
二、OpenResty安装
首先你的Linux虚拟机必须联网
2.1 安装开发库
首先要安装OpenResty的依赖开发库,执行命令:
yum install -y pcre-devel openssl-devel gcc --skip-broken
2.2 安装OpenResty仓库
你可以在你的 CentOS 系统中添加 openresty
仓库,这样就可以便于未来安装或更新我们的软件包(通过 yum check-update
命令)。运行下面的命令就可以添加我们的仓库:
yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo
如果提示说命令不存在,则运行:
yum install -y yum-utils
然后再重复上面的命令
2.3 安装OpenResty
然后就可以像下面这样安装软件包,比如 openresty
:
yum install -y openresty
2,4 安装opm工具
opm是OpenResty的一个管理工具,可以帮助我们安装一个第三方的Lua模块。
如果你想安装命令行工具 opm
,那么可以像下面这样安装 openresty-opm
包:
yum install -y openresty-opm
2.5 目录结构
默认情况下,OpenResty安装的目录是:/usr/local/openresty
OpenResty就是在Nginx基础上集成了一些Lua模块。
2.6 配置nginx的环境变量
打开配置文件:
vi /etc/profile
在最下面加入两行:
export NGINX_HOME=/usr/local/openresty/nginx
export PATH=${NGINX_HOME}/sbin:$PATH
NGINX_HOME:后面是OpenResty安装目录下的nginx的目录
然后让配置生效:
source /etc/profile
2.7 启动和运行
OpenResty底层是基于Nginx的
,查看OpenResty目录的nginx目录
所以运行方式与nginx基本一致:
# 启动nginx
nginx
# 重新加载配置
nginx -s reload
# 停止
nginx -s stop
修改/usr/local/openresty/nginx/conf/nginx.conf
文件,内容如下:
#user nobody;
worker_processes 1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 8081;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
在Linux的控制台输入命令以启动nginx:
nginx
启动nginx后访问,替换自己的ip,端口8081.如何有安全组,则放开
三、使用步骤
我们需要在OpenResty中编写业务,
查询商品数据并返回到浏览器。
但是这次,我们先在OpenResty接收请求,返回假的商品数据。
3.1 添加对OpenResty的Lua模块的加载
OpenResty的很多功能都依赖于其目录下的Lua库,需要在nginx.conf中指定依赖库的目录,修改/usr/local/openresty/nginx/conf/nginx.conf
文件,在其中的http
下面,添加下面代码
#lua 模块
lua_package_path "/usr/local/openresty/lualib/?.lua;;";
#c模块
lua_package_cpath "/usr/local/openresty/lualib/?.so;;";
3.2 OpenResty监听请求
监听/api/item路径,
响应结果由lua/item.lua文件来决定
修改/usr/local/openresty/nginx/conf/nginx.conf
文件,在nginx.conf的server下面,添加对/api/item这个路径的监听:
location /api/item {
# 默认的响应类型
default_type application/json;
# 响应结果由lua/item.lua文件来决定
content_by_lua_file lua/item.lua;
}
3.3 编写item.lua
在/usr/loca/openresty/nginx
目录创建文件夹:lua
在/usr/loca/openresty/nginx/lua
文件夹下,新建文件:item.lua
编写item.lua,返回假数据
item.lua中,利用ngx.say()
函数返回数据到Response中
ngx.say('{"id":10010,"name":"桌子","title":"桌子出售","price":1000,"createTime":"2024-09-21T16:00:00.000+00:00"}')
3.4 重新加载配置
nginx -s reload
成功显示
四、请求参数处理
上述我们在OpenResty接收前端请求,但是返回的是假数据。
要返回真实数据,必须根据前端传递来的商品id,查询商品信息才可以。
那么如何获取前端传递的商品参数
呢?
4.1 获取参数的API
OpenResty中提供了一些API用来获取不同类型的前端请求参数:
4.2 获取参数并返回
可以发现上述中使用的时路径占位符,所以使用api中的正则表达式获取
-
修改
/usr/loca/openresty/nginx/nginx.conf
文件中监听/api/item的代码,利用正则表达式获取ID:location ~ /api/item/(\d+) { # 默认的响应类型 default_type application/json; # 响应结果由lua/item.lua文件来决定 content_by_lua_file lua/item.lua; }
-
修改
/usr/loca/openresty/nginx/lua/item.lua
文件,获取id并拼接到结果中返回:下图为我主页文章:lua基本语法使用
可自行查看
语法---可以使用操作符…(两个点)
print("hello".."world")
-- 获取商品id local id = ngx.var[1] -- -- 拼接并返回 ngx.say('{"id":'..id..',"name":"桌子","title":"桌子出售","price":1000,"createTime":"2024-09-21T16:00:00.000+00:00"}')
结果成功
说明我们请求参数获取成功
五、发送http请求的API
local resp = ngx.location.capture("/path",{
method = ngx.HTTP_GET, -- 请求方式
args = {a=1,b=2}, -- get方式传参数
body = "c=3&d=4" -- post方式传参
})
返回的响应内容包括:
- resp.status:响应状态码
- resp.header:响应头,是一个table
- resp.body:响应体,就是响应数据
注意
:这里的path是路径,并不包含IP和端口。这个请求会被nginx内部的server监听并处理。
但是我们希望这个请求发送到Tomcat服务器(后端),所以还需要编写一个server来对这个路径做反向代理:
location /path {
proxy_pass http://192.168.130.1:8081;
}
5.1 封装http工具
我们封装一个发送Http请求的工具,基于ngx.location.capture来实现查询,方便后续使用
之前我们说过,OpenResty启动时会加载以下两个目录中的工具文件:
所以,自定义的http工具也需要放到这个目录下。
- 在
/usr/local/openresty/lualib
目录下,新建一个common.lua
文件(公共函数封装)
这个工具将
read_http
函数封装到_M
这个table类型的变量中,并且返回,这类似于导出。
使用的时候,可以利用require('common')
来导入该函数库,这里的common是函数库的文件名。
-- 封装函数,发送http请求,并解析响应
local function read_http(path, params)
local resp = ngx.location.capture(path,{
method = ngx.HTTP_GET,
args = params,
})
if not resp then
-- 记录错误信息,返回404
ngx.log(ngx.ERR, "http请求查询失败, path: ", path , ", args: ", args)
ngx.exit(404)
end
return resp.body
end
-- 将方法导出
local _M = {
read_http = read_http
}
return _M
- 使用http函数发送请求,实现商品查询
修改/usr/local/openresty/lua/item.lua
文件,利用刚刚封装的函数库实现查询
-- 引入自定义common工具模块,返回值是common中返回的 _M
local common = require("common")
-- 从 common中获取read_http这个函数
local read_http = common.read_http
-- 获取路径参数
local id = ngx.var[1]
-- 根据id查询商品
local itemJSON = read_http("/item/".. id, nil)
-- 返回结果
ngx.say(itemJSON)
六、cjson的模块用来处理JSON的序列化和反序列化
官方地址
:https://github.com/openresty/lua-cjson/
1)引入cjson模块:
local cjson = require "cjson"
2)序列化:
local obj = {
name = 'jack',
age = 21
}
-- 把 table 序列化为 json
local json = cjson.encode(obj)
3)反序列化:
local json = '{"name": "jack", "age": 21}'
-- 反序列化 json为 table
local obj = cjson.decode(json);
print(obj.name)
七、OpenResty提供了操作Redis的模块
7.1 封装Redis工具
为了方便,我们将Redis操作封装到之前的common.lua工具库中。
修改/usr/local/openresty/lualib/common.lua
文件:
-- 导入redis
local redis = require('resty.redis')
-- 初始化redis
local red = redis:new()
red:set_timeouts(1000, 1000, 1000)
-- 关闭redis连接的工具方法,其实是放入连接池
local function close_redis(red)
local pool_max_idle_time = 10000 -- 连接的空闲时间,单位是毫秒
local pool_size = 100 --连接池大小
local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)
if not ok then
ngx.log(ngx.ERR, "放入redis连接池失败: ", err)
end
end
-- 查询redis的方法 ip和port是redis地址,key是查询的key
local function read_redis(ip, port, key)
-- 获取一个连接
local ok, err = red:connect(ip, port)
if not ok then
ngx.log(ngx.ERR, "连接redis失败 : ", err)
return nil
end
-- 查询redis
local resp, err = red:get(key)
-- 查询失败处理
if not resp then
ngx.log(ngx.ERR, "查询Redis失败: ", err, ", key = " , key)
end
--得到的数据为空处理
if resp == ngx.null then
resp = nil
ngx.log(ngx.ERR, "查询Redis数据为空, key = ", key)
end
close_redis(red)
return resp
end
-- 封装函数,发送http请求,并解析响应
local function read_http(path, params)
local resp = ngx.location.capture(path,{
method = ngx.HTTP_GET,
args = params,
})
if not resp then
-- 记录错误信息,返回404
ngx.log(ngx.ERR, "http查询失败, path: ", path , ", args: ", args)
ngx.exit(404)
end
return resp.body
end
-- 将方法导出
local _M = {
read_http = read_http,
read_redis = read_redis
}
return _M
7.2 实现Redis查询
修改/usr/local/openresty/lua/item.lua
文件,添加一个查询函数:
-- 导入common函数库
local common = require('common')
local read_http = common.read_http
local read_redis = common.read_redis
-- 导入cjson库
local cjson = require('cjson')
-- 封装查询函数 先查询redis,再查http
function read_data(key, path, params)
-- 查询redis
local val = read_redis("127.0.0.1", 6379, key)
-- 判断redis是否命中
if not val then
ngx.log(ngx.ERR, "redis查询失败,尝试查询http, key: ", key)
-- redis查询失败,去查询http
val = read_http(path, params)
end
-- 返回数据
return val
end
-- 获取路径参数
local id = ngx.var[1]
-- 查询商品信息
local itemJSON = read_data("item:id:" .. id, "/item/" .. id, nil)
ngx.say(itemJSON)
最终重新加载
nginx -s reload
八、Nginx本地缓存
8.1 本地缓存API
OpenResty为Nginx提供了shard dict的功能,可以在nginx的多个worker之间共享数据,实现缓存功能。
- 开启共享字典,在nginx.conf的http下添加配置:
# 共享字典,也就是本地缓存,名称叫做:item_cache,大小150m lua_shared_dict item_cache 150m;
- 操作共享字典:
-- 获取本地缓存对象
local item_cache = ngx.shared.item_cache
-- 存储, 指定key、value、过期时间,单位s,默认为0代表永不过期
item_cache:set('key', 'value', 1000)
-- 读取
local val = item_cache:get('key')
8.2 实现本地缓存查询
修改/usr/local/openresty/lua/item.lua
文件,修改read_data查询函数,添加本地缓存逻辑:
-- 导入common函数库
local common = require('common')
local read_http = common.read_http
local read_redis = common.read_redis
-- 导入cjson库
local cjson = require('cjson')
-- 导入共享词典,本地缓存
local item_cache = ngx.shared.item_cache
-- 封装查询函数
function read_data(key, expire, path, params)
-- 查询本地缓存
local val = item_cache:get(key)
if not val then
ngx.log(ngx.ERR, "本地缓存查询失败,尝试查询Redis, key: ", key)
-- 查询redis
val = read_redis("127.0.0.1", 6379, key)
-- 判断查询结果
if not val then
ngx.log(ngx.ERR, "redis查询失败,尝试查询http, key: ", key)
-- redis查询失败,去查询http
val = read_http(path, params)
end
end
-- 查询成功,把数据写入本地缓存
item_cache:set(key, val, expire)
-- 返回数据
return val
end
-- 获取路径参数
local id = ngx.var[1]
-- 查询商品信息
local itemJSON = read_data("item:id:" .. id, 1800, "/item/" .. id, nil)
ngx.say(itemJSON)
最终重新加载
nginx -s reload
成功获取数据