OpenResty 使用示例
protocal 转换
location ~ ^/api/([-_a-zA-Z0-9/]+).json {
access_by_lua_file /path/to/lua/api/protocal_decode.lua;
content_by_lua_file /path/to/lua/api/$1.lua;
body_filter_by_lua_file /path/to/lua/api/protocal_encode.lua;
}
- API 设计,添加自己 的 HTTP api 规范地址
location ~ ^/app/([-_a-zA-Z0-9/]+) {
set $path $1;
content_by_lua_file /path/to/lua/app/root/$path.lua;
}
实现 IP 限制
init_by_lua_block {
local iputils = require("resty.iputils")
iputils.enable_lrucache()
local whitelist_ips = {
"127.0.0.1",
"10.10.10.0/24",
"192.168.0.0/16",
}
-- WARNING: Global variable, recommend this is cached at the module level
-- https://github.com/openresty/lua-nginx-module#data-sharing-within-an-nginx-worker
whitelist = iputils.parse_cidrs(whitelist_ips)
}
access_by_lua_block {
local iputils = require("resty.iputils")
if not iputils.ip_in_cidrs(ngx.var.remote_addr, whitelist) then
return ngx.exit(ngx.HTTP_FORBIDDEN)
end
}
access_by_lua_block {
if ngx.var.remote_addr == "1.1.1.1" then
local headers = ngx.req.get_headers()
for k,v in pairs(headers) do
ngx.log(ngx.ERR , "header ", k, ": ", v)
end
ngx.log(ngx.ERR , "request_body: ", ngx.var.request_body)
end
}
代理其他API
使用 http 客户端代理 http 请求
opm install pintsized/lua-resty-http
location /test {
content_by_lua_block {
ngx.req.read_body()
local args, err = ngx.req.get_uri_args()
local http = require "resty.http"
local httpc = http.new()
httpc:set_timeout(1000) -- 1000ms
-- https://docs.github.com/zh/rest/guides/getting-started-with-the-rest-api?apiVersion=2022-11-28&tool=curl#using-body-parameters
local res, err = httpc:request_uri("https://api.github.com/repos/octocat/Spoon-Knife/issues", {
method = "POST",
body = args.data,
headers = {
["Accept"] = "Accept",
["Authorization"] = "Bearer YOUR-TOKEN",
}
})
if 200 ~= res.status then
ngx.exit(res.status)
end
if args.key == res.body then
ngx.say("valid request")
else
ngx.say("invalid request")
end
}
}
快速响应终端
ngx.say("xxx")
ngx.eof()
- 下面处理其它逻辑
限速
限速分以下几种
- limit_rate 限制响应速度
- limit_conn 限制连接数
- limit_req 限制请求数
限制响应速度
access_by_lua_block {
-- 设定当前请求的响应上限是 每秒 300K 字节
ngx.var.limit_rate = "300K"
}
限制连接数和请求数
需要使用 openresty/lua-resty-limit-traffic 库,用于限制和控制OpenResty流量,包括请求、连接数、流量
lua_code_cache on;
# 注意 limit_conn_store 的大小需要足够放置限流所需的键值。
# 每个 $binary_remote_addr 大小不会超过 16 字节(IPv6 情况下),算上 lua_shared_dict 的节点大小,总共不到 64 字节。
# 100M 可以放 1.6M 个键值对
lua_shared_dict limit_conn_store 100M;
server {
listen 8080;
location / {
access_by_lua_file src/access.lua;
content_by_lua_file src/content.lua;
log_by_lua_file src/log.lua;
}
}
local limit_conn = require "resty.limit.conn"
-- new 的第四个参数用于估算每个请求会维持多长时间,以便于应用漏桶算法
local limit, limit_err = limit_conn.new("limit_conn_store", 10, 2, 0.05)
if not limit then
error("failed to instantiate a resty.limit.conn object: ", limit_err)
end
local _M = {}
function _M.incoming()
local key = ngx.var.binary_remote_addr
local delay, err = limit:incoming(key, true)
if not delay then
if err == "rejected" then
return ngx.exit(503)
end
ngx.log(ngx.ERR, "failed to limit req: ", err)
return ngx.exit(500)
end
if limit:is_committed() then
local ctx = ngx.ctx
ctx.limit_conn_key = key
ctx.limit_conn_delay = delay
end
if delay >= 0.001 then
ngx.log(ngx.WARN, "delaying conn, excess ", delay,
"s per binary_remote_addr by limit_conn_store")
ngx.sleep(delay)
end
end
function _M.leaving()
local ctx = ngx.ctx
local key = ctx.limit_conn_key
if key then
local latency = tonumber(ngx.var.request_time) - ctx.limit_conn_delay
local conn, err = limit:leaving(key, latency)
if not conn then
ngx.log(ngx.ERR,
"failed to record the connection leaving ",
"request: ", err)
end
end
end
return _M
local limit_conn = require "utils.limit_conn"
-- 对于内部重定向或子请求,不进行限制。因为这些并不是真正对外的请求。
if ngx.req.is_internal() then
return
end
limit_conn.incoming()
local limit_conn = require "utils.limit_conn"
limit_conn.leaving()
域名解析
- 使用
resolver 1.1.1.1 223.5.5.5 valid=600s;
resty.dns.resolver
安装 lua-casbin
/usr/local/openresty/luajit/bin/luarocks install lrexlib-pcre PCRE_DIR=/usr/local/openresty/pcre
GIT_SSL_NO_VERIFY=1 /usr/local/openresty/luajit/bin/luarocks install casbin
代理&cache vscode 源
- cache-update-visualstudio.lua
-- from https://github.com/xiexianbin/openresty-demo/blob/master/lua/cache-update-visualstudio.lua
-- vscode node_server 加速实现
-- 获取数据,原始数据在 https://update.code.visualstudio.com/commit:<ID>/server-linux-x64/stable
-- 若存在缓存,返回缓存,否则去国内cdn地址 https://vscode.cdn.azure.cn/stable/<commit-id>/<vscode-server-linux-x64.tar.gz> 获取,并缓存
-- opm install ledgetech/lua-resty-http
-- mkdir -p /data/vscode-server
-- chmod -R 777 /data/vscode-server
-- ref https://www.xiexianbin.cn/software/dev/vscode/index.html
local http = require "resty.http"
local ngx = require("ngx")
local cache_dir = "/data/vscode-server"
-- download file from cdn and cache it and response to client
local function download_file(commit_id, file_dir, file_name)
local url = "https://vscode.cdn.azure.cn/stable/" .. commit_id .. "/vscode-server-linux-x64.tar.gz"
ngx.log(ngx.ERR, "cdn url is " .. url)
-- create dir
os.execute('whoami && mkdir -p ' .. file_dir)
-- http client
local httpc = http.new()
httpc:set_timeout(10000)
local res, err = httpc:request_uri(url, {
method = "GET",
ssl_verify = false,
})
-- cache file to local
local file_path = file_dir .. "/" .. file_name
if res and res.status == 200 then
local file = io.open(file_path, "w")
file:write(res.body)
file:close()
-- 获取失败
else
ngx.log(ngx.ERR, "Failed to download file: ", err)
end
httpc:close()
end
local function main(commit_id)
local file_dir = cache_dir .. "/" .. commit_id .. "/"
local file_name = "vscode-server-linux-x64.tar.gz"
local file_path = file_dir .. "/" .. file_name
local file = io.open(file_path, "r")
if file then
ngx.say(file:read("*all"))
file:close()
else
download_file(commit_id, file_dir, file_name)
ngx.exec(ngx.var.uri)
end
end
local request_uri = ngx.var.uri
ngx.log(ngx.ERR, "request uri: ", request_uri)
local commit_id = string.sub(ngx.var.uri, 9, 48)
ngx.log(ngx.ERR, "commit_id is: ", commit_id)
main(commit_id)
- update.code.visualstudio.com.conf
server {
listen 8002;
server_name update.code.visualstudio.com;
resolver 8.8.8.8;
access_log logs/update.code.visualstudio.com_access.log debug;
error_log logs/update.code.visualstudio.com_error.log;
# curl http://update.code.visualstudio.com:8002/commit:3c4e3df9e89829dce27b7b5c24508306b151f30d/server-linux-x64/stable
location ^~ /commit: {
content_by_lua_file lua/cache-update-visualstudio.lua;
}
location / {
proxy_pass https://update.code.visualstudio.com;
}
}