破解 api Gateway Panich:"X in new path conflicts with existing wildcard Y in existing prefix Z"

krakend api gateway panic: "X in new path conflicts with existing wildcard Y in existing prefix Z"

我有两个 Web 服务,我想使用 krakend API 网关管理由前缀分隔的两个端点。

以下是我的配置:

{
  "version": 2,
  "name": "My API Gateway",
  "port": 8080,
  "host": [],
  "endpoints": [
    {
      "endpoint": "/api/entity/{entityID}",
      "output_encoding": "no-op",
      "method": "POST",
      "backend": [
        {
          "url_pattern": "/api/entity/{entityID}",
          "encoding": "no-op",
          "host": [
            "http://987.654.32.1"
          ]
        }
      ]
    },
    {
      "endpoint": "/api/entity/member/assign/{userID}",
      "output_encoding": "no-op",
      "method": "GET",
      "backend": [
        {
          "url_pattern": "/api/entity/member/assign/{userID}",
          "encoding": "no-op",
          "host": [
            "http://123.456.789.0"
          ]
        }
      ]
    }
  ]
}

当我运行它时,出现错误:

panic: 'member' in new path '/api/entity/member/assign/:userID' conflicts with existing wildcard ':entityID' in existing prefix '/api/entity/:entityID'

据我了解,第一个端点上的 {entityID} 似乎与第二个端点上的 /member/ 冲突。此错误是预期行为还是我的配置文件有任何问题?

这是 KrakenD 内部使用的 Gin library 的已知限制,您可以使用此 go 代码直接在库中重现此行为,这将重现完全相同的问题:

package main

import "github.com/gin-gonic/gin"

func main() {
    r := gin.New()
    r.GET("/ping", handler)
    r.GET("/ping/foo", handler)
    r.GET("/ping/:a", handler)
    r.GET("/ping/:a/bar", handler)
}

func handler(c *gin.Context) {
    c.JSON(200, gin.H{
        "message": "pong",
    })
}

参见this issue中的代码。

解决方案是声明不与其他端点的子集冲突的端点路径。在您的配置中,端点 /api/entity/member/assign/{userID}/api/entity/{entityID}.

的子集

请注意 {placeholders} 就像使用通配符一样,因此您的第一个端点可以在其他系统中表达,例如 /api/entity/*,因此 /api/entity/member/assign/{userID} 是正匹配。

在通配符不冲突的情况下对您的配置进行任何细微更改都可以解决此问题。例如,以下两个端点适合您:

/api/entity/find/{entityID}
/api/entity/member/assign/{userID}

感谢@alo 对这个问题的解释。

我遇到过同样的情况,因为我有以下方式的 krakend 端点:

GET: /v1/projects/{project_uuid}

GET: /v1/projects/{project_key}/portfolio

但令人惊讶的是,像这样欺骗 krakenD 效果很好。

GET: /v1/projects/{key}  // In swagger docs mentioned this key to be supplied as uuid

GET: /v1/projects/{key}/portfolio // In swagger docs mentioned this key to be supplied as string

现在这个端点按预期触发我的后端客户端。希望这个烦人的事情得到解决。