网关不是“转发器”这么简单。它通常至少要做五件事:
- 入口统一接入
- 认证鉴权
- 流量治理
- 动态路由
- 可观测性
OpenResty 的强项在于:这些能力你可以按自己业务把它们拼成一条插件链。
先看一个简化版可编程网关配置:
worker_processes auto;
events {
worker_connections 8192;
}
http {
lua_package_path "lua/?.lua;;";
lua_shared_dict rate_store 20m;
upstream backend_main {
server 127.0.0.1:9001;
}
upstream backend_canary {
server 127.0.0.1:9002;
}
server {
listen 8080;
set $target_upstream backend_main;
location / {
rewrite_by_lua_block {
require("gateway.rewrite").run()
}
access_by_lua_block {
require("gateway.access").run()
}
proxy_set_header X-Request-Id $request_id;
proxy_set_header X-User-Id $http_x_user_id;
proxy_pass http://$target_upstream;
header_filter_by_lua_block {
require("gateway.response").header()
}
log_by_lua_block {
require("gateway.log").run()
}
}
}
}#gateway/rewrite.lua
local _M = {}
function _M.run()
local uri = ngx.var.uri
if uri == "/ping" then
ngx.req.set_uri("/health")
end
end
return _M#gateway/access.lua
local _M = {}
local function unauthorized(msg)
ngx.status = 401
ngx.header["Content-Type"] = "application/json"
ngx.say('{"error":"' .. msg .. '"}')
return ngx.exit(401)
end
function _M.run()
local headers = ngx.req.get_headers()
local token = headers["authorization"]
if token ~= "Bearer demo-token" then
return unauthorized("unauthorized")
end
if headers["x-canary"] == "1" then
ngx.var.target_upstream = "backend_canary"
end
end
return _M#gateway/response.lua
local _M = {}
function _M.header()
ngx.header["X-Gateway"] = "openresty"
end
return _M#gateway/log.lua
local _M = {}
function _M.run()
ngx.log(
ngx.NOTICE,
"request_id=", ngx.var.request_id,
" upstream=", ngx.var.target_upstream,
" status=", ngx.status
)
end
return _M这个例子已经体现出网关的基本骨架:
rewrite 负责改写入口
access 负责放行决策
proxy 负责转发
filter 负责回程统一加工
log 负责收尾记录