我们内部核心的结算微服务上周又被脏数据搞崩溃了。起因是一个前端表单校验逻辑被恶意爬虫直接绕过,把一个包含负数金额和超长非法字符的订单 Payload 怼进了内网。因为历史包袱太重,底层的 Go 微服务在接收到请求后,硬编码的业务校验漏掉了极端边界值,导致数据库底层算账溢出,触发了连锁雪崩。

天天去吐槽业务开发写 Bug 解决不了根本问题。把防御逻辑后退到微服务本身,不仅心智负担极重,而且不同开发人员写出来的校验标准千奇百怪。我们一合计,干脆把大门关紧,在流量入口的 API 网关层(我们用的是 APISIX)直接做请求 Payload 的强验证。只要是不符合 Swagger/OpenAPI 定义的脏数据,连进入我们内网微服务的机会都没有,直接在网关层弹回 400。

APISIX 内置的 request-validation 插件非常适合干这个事情。它可以直接接收标准的 JSON Schema 定义。我们通过自动化脚本,将开发团队维护的 OpenAPI 定义文档定期提取出对应的 Schema 参数定义,然后通过 Admin API 动态同步更新到网关路由中。

以下是我们生产环境配置的一条典型 APISIX 路由规则,展示了如何配置 request-validation 插件来拦截不符合规范的下单请求:

{
  "uri": "/api/v1/orders",
  "name": "create-order-route",
  "methods": ["POST"],
  "plugins": {
    "request-validation": {
      "body_schema": {
        "type": "object",
        "required": ["userId", "items", "paymentMethod"],
        "properties": {
          "userId": {
            "type": "integer",
            "minimum": 1
          },
          "items": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "object",
              "required": ["productId", "quantity", "price"],
              "properties": {
                "productId": {
                  "type": "string",
                  "pattern": "^prod_[a-zA-Z0-9]{16}$"
                },
                "quantity": {
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 99
                },
                "price": {
                  "type": "number",
                  "minimum": 0.01
                }
              },
              "additionalProperties": false
            }
          },
          "paymentMethod": {
            "type": "string",
            "enum": ["wechat", "alipay", "credit_card"]
          }
        },
        "additionalProperties": false
      },
      "rejected_code": 400,
      "rejected_msg": "请求参数不合法,请检查传入结构是否符合 OpenAPI 规范定义"
    },
    "proxy-rewrite": {
      "headers": {
        "set": {
          "X-Gateway-Validated": "true"
        }
      }
    }
  },
  "upstream": {
    "nodes": {
      "10.0.8.25:8080": 1
    },
    "type": "roundrobin"
  }
}

配置上线之后,我们做过一轮压测。网关层解析 JSON Schema 确实会带来一定的 CPU 损耗,在 QPS 到达 5000 以上时,网关的响应时延(Latency)大概增加了 1.8ms。但相比于脏数据引发的核心微服务数据库慢查询甚至雪崩,这点性能开销完全在接受范围内。

另外一个比较大的坑是网关的版本兼容性。有时候后端微服务发布新版本,字段还没在网关更新,前端发来的请求就全被拦截了,所以在 CI/CD 流程中必须把“网关 Schema 刷新”作为热发布的一环。

大家线上有在网关层做强约束验证吗?如果有大规模的 API 变动,你们是如何保证 API 文档和网关 Schema 实时同步的?