🍓 简介:java系列技术分享(👉持续更新中…🔥)
🍓 初衷:一起学习、一起进步、坚持不懈
🍓 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正🙏
🍓 希望这篇文章对你有所帮助,欢迎点赞 👍 收藏 ⭐留言 📝

🍓 更多文章请点击
在这里插入图片描述在这里插入图片描述

一、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中的正则表达式获取

  1. 修改/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;
    }
    

    在这里插入图片描述

  2. 修改/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工具也需要放到这个目录下。

  1. /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
  1. 使用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之间共享数据,实现缓存功能。

  1. 开启共享字典,在nginx.conf的http下添加配置:
     # 共享字典,也就是本地缓存,名称叫做:item_cache,大小150m
     lua_shared_dict item_cache 150m; 
    
  2. 操作共享字典:
-- 获取本地缓存对象
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

成功获取数据
在这里插入图片描述

在这里插入图片描述在这里插入图片描述

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐