8

APISIX高级路由之通过Body参数转发请求

 2 years ago
source link: https://zhang.ge/5157.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
WEB应用

APISIX高级路由之通过Body参数转发请求

Jager · 10月28日 · 2021年APISIX · API网关 · nginx 74次已读

最近在主导部门统一接入服务项目,其中涉及7层网关组件的选型。在过去一年多时间内,我们部门的业务主要使用的Kong网关,也打算作为一个长期方案,结果杀出了APISIX这个黑马,经过分析讨论,最终敲定基于APISIX来开发统一接入服务。所以,最近有一些零散的折腾存货,会陆续整理到博客,方便有相同诉求的朋友。

APISIX的高级路由非常厉害,可以基于任意变量来做转发路由,比如可以基于Header、cookie、querystring参数等。而我们这里历史上有个非常变态的用法:基于Body里面某个参数的值来路由,即不同的值要转发到不同的后端IP:PORT(这个问题主要是因为服务拆分时偷懒,没有推动客户端修改请求留下的尾巴)。

APISIX前面的版本中,发现并不支持解析Body然后通过Body里面的指定参数来做路由,最近更新到2.10.0 LTS版本后,发现这个特性赫然支持了:

如下表所示,目前APISIX的route里面已经支持植入一个lua函数,那么就变得非常灵活了!因此,上面这个变态需求也成为了可能。

根据需求,写了如下lua函数,意思是当body里面有个foo参数且值为bar的时候命中此路由:

function(vars)
local core = require ('apisix.core')
local body, err = core.request.get_body()
if not body then
return false
local data, err = core.json.decode(body)
if not data then
return false
-- 当匹配body里面foo字段等于bar的时候,路由生效
if data['foo'] == 'bar' then
return true
return false

加到APISIX的路由当中,示例代码如下(这里关键是需要加\n来换行):

"uri": "/hello",
"filter_func": "function(vars)\n local core=require ('apisix.core')\n local body, err=core.request.get_body()\n if not body then\n return false\n end\n\n local data, err=core.json.decode(body)\n if not data then\n return false\n end\n\n if data['foo']=='bar' then\n return true\n end\n\n return false\nend",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1": 9080
"status": 1

需要注意的是,加了这条路由之后,对 /hello 的所有请求都会命中到这个路由,并不会因为Body里面没有foo或者foo的值不为bar而出现404报错。这里也不太理解官方的设计逻辑,可能是因为此时只有一条路由,已经没有其他选择了。

因此,还需要加一条不含过滤的路由,转发到另一个后端,协议如下:

"uri": "/hello",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1": 9081
"status": 1

此时,请求才能正常被区分开来,即请求Body里面带了foo且值为bar的请求,会转发到9080端口,否则转发到9081端口。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK