如果在 API 端点路由中传递@RequestParam,Istio 虚拟服务会返回 404

Istio Virtual Service gives 404 if passed @RequestParam in API end points routing

我想通过 Istio 虚拟服务路由到我的微服务。当我在前缀中使用基于 @RequestParam 的输入时,甚至在精确输入时,它会为 /api/cities/{city_id}/tours 抛出 404,但其余的工作正常。

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: app
  namespace: nsapp
spec:
  gateways:
    - app-gateway
  hosts:
    - app.*.*.*
  http:
  - match:
    - uri:
        prefix: "/api/cities/{city_id}/tours"
    - uri:
        prefix: "/api/countries/{country_id}/cities"
    - uri:
        prefix: "/api/countries"
    route:
    - destination:
        host: appservice
        port:
          number: 9090

前缀匹配匹配文字字符串。

/api/countries 也匹配您打算与 /api/countries/{country_id}/cities

匹配的内容

/api/cities/{city_id}/tours 但是,不起作用。

对于更复杂的匹配,您可以使用精确匹配和正则表达式,如 VirtualService 文档中所述。

也许是这样的(未经测试):

exact: "/api/countries"
regex: "/api/countries/[^/]*/cities"

这个片段

    - uri:
        prefix: "/api/cities/{city_id}/tours"
    - uri:
        prefix: "/api/countries/{country_id}/cities"

会按字面意思理解。 {city_id}{country_id} 不会替换为您的自定义 ID。此时,istio 将查找字面意思为 /api/cities/{city_id}/tours/api/countries/{country_id}/cities 的前缀,该前缀不存在(您会收到错误 404)。如果要将表达式与自定义 ID 匹配,则必须使用正则表达式。看看this doc. There you will find information about the capabilities of the StringMatch: exact, prefix or regex. You can find the syntax of the regular expressions used in istio here.

总结: 您应该将 prefix 更改为 regex,然后创建您自己的正则表达式以匹配您的自定义 ID。示例:

    - uri:
        regex: "/api/cities/[a-zA-Z]+/tours"
    - uri:
        regex: "/api/countries/[a-zA-Z]+/cities"

在我的示例中,ID 中只有字母(大写或小写)。在这里,您必须根据 this documentation.

创建自己的正则表达式

方法一:-

我尝试了以下方法并发现它可以工作,添加了我测试过并且正在工作的解决方案。基本上,执行的步骤是:-

删除前缀:“/api/countries/{country_id}/cities” 因为 /api/countries/ 是 2 个 API 的通用字符串,最终,它能够路由到原始应用服务主机上的 API 分别与 /api/cities.

相同
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: app
  namespace: nsapp
spec:
  gateways:
    - app-gateway
  hosts:
    - app.*.*.*
  http:
  - match:
    - uri:
        prefix: "/api/cities"
    - uri:
        prefix: "/api/countries"
    route:
    - destination:
        host: appservice
        port:
          number: 9090