常用的有API网关如traefik、Tyk,这些组件提供整套的API路由方法,支持路由图形化界面管理,本文将介绍一个通过nginx使用的方案。
nginx用于Api转发具有极好的性能,nginx通常用于静态的资源转发,接口按照正则表达式通配路由,对于需要动态调整的接口,略显无力,如何做?
nginx.conf
说明:auth_request,可以对指定形式的接口进行鉴权,带回cookie或者其他鉴权内容,根据返回进行处理;
权限、路由等下信息在mysql.lua中访问。
location /router/ {
auth_request /auth; # 鉴权
set $value '';
if ( $request_uri ~ "^/router/([-a-zA-Z0-9]+)(.*)$" ) {
set $key $1;
rewrite_by_lua_file /usr/local/openresty/mysql.lua;
}
proxy_pass http://$value;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
}
mysql.lua
说明:读取mysql路由或者其他需要的信息,返回给nginx.conf中进行路由操作
-- 从上下文读取需要寻找的key
local key = ngx.var.key
local mysql = require "xxx"
local db, err = mysql:new()
if not db then
ngx.log(ngx.ERR, "failed to instantiate mysql: ", err)
return
end
db:set_timeout(1000) -- 1 sec
local ok, err, errcode, sqlstate = db:connect{
host = "ip",
port = "port",
database = "xx",
user = "xx",
password = "*****",
charset = "utf8",
max_packet_size = 1024 * 1024,
}
if not ok then
ngx.log(ngx.ERR, "failed to connect: ", err, ": ", errcode, " ", sqlstate)
return
end
local name = ngx.quote_sql_str(key)
res, err, errcode, sqlstate = db:query("some SQL", 1)
if res == ngx.null or res == nil or #res == 0 then
ngx.log(ngx.ERR, "no resources from mysql")
-- 直接返回错误信息
ngx.header['Content-Type'] = 'text/plain'
ngx.say("服务地址 "..name.." not found")
return ngx.exit(200)
else
-- 读出记录,并且更新cache
route = res[1]["server"]
end
-- 更新上下文中的value
ngx.var.value = route
nginx+lua推荐使用openresty,支持国产!
从根据Api中的uri或者参数,通过lua提取,结合mysql中的业务关系,可以是想动态路由功能。