WEB应用

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

Jager · 10月28日 · 2021年 · · 242次已读

最近在主导部门统一接入服务项目,其中涉及 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
    end
  
    local data, err = core.json.decode(body)
    if not data then
        return false
    end
  
    -- 当匹配 body 里面 foo 字段等于 bar 的时候,路由生效
    if data['foo'] == 'bar' then
        return true
    end
  
    return false
  end

加到 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 端口。

0 条回应
  1. 马内 2021-10-29 · 18:59

    网站每日ip 1千,交换友链,https://money1.us/521

  2. yndsht 2021-11-3 · 9:26

    老张干啥去了,这么久不更新博客了,今天终于更新了!