PAYATHON 2026

为什么 WireMock 无法按请求 Header 正确匹配?

支付老李

结论

Header 匹配语法没有明显问题。根据日志,WireMock 实际命中的并不是展示出来的两条配置:

{
  "status": 201,
  "bodyFileName": "status.json"
}

第一条配置使用的响应文件却是 payment-consents.json。这意味着当前实例中还有一条匹配相同 method + url 的 stub,或者修改后的 routes.json 没有被当前容器正确加载。

最可能的原因

1. 存在未限定 Header 的旧路由

WireMock 中可能还保留着类似的配置:

{
  "request": {
    "method": "POST",
    "url": "/middleware-nz-sandbox/v2.0/domestic-payment-consents"
  },
  "response": {
    "status": 201,
    "bodyFileName": "status.json"
  }
}

这条规则不检查 x-fapi-interaction-id,所以任何发往该 URL 的 POST 请求都可能命中它。

如果多个 stub 同时满足请求,又没有明确设置 priority,WireMock 的最终选择还会受到加载顺序等因素影响。因此,不要依赖 JSON 文件中的排列顺序来处理规则冲突。

2. routes.json 没有作为 WireMock mapping 文件加载

Standalone WireMock 通常从文件根目录下的 mappings 目录加载 stub,并从 __files 目录读取响应文件。建议采用下面的目录结构:

wiremock/
├── mappings/
│   ├── payment-consents-okay.json
│   └── payment-consents-error.json
└── __files/
    ├── payment-consents.json
    └── payment-consents-error.json

如果 Docker volume 挂载到了错误的目录,容器使用了不同的文件根目录,或者 routes.json 的顶层结构不符合当前加载方式,WireMock 可能仍在使用镜像内、旧 volume 中或其他目录里的 mapping。

另外,宿主机文件发生变化后,WireMock 通常不会自动重新加载所有文件 mapping。修改配置后,应重启容器,或者通过 Admin API 重新导入或 reset mappings。

建议配置

把两条规则拆成独立的 mapping 文件,并明确设置优先级。

mappings/payment-consents-okay.json:

{
  "priority": 1,
  "request": {
    "method": "POST",
    "urlPath": "/middleware-nz-sandbox/v2.0/domestic-payment-consents",
    "headers": {
      "x-fapi-interaction-id": {
        "equalTo": "okay"
      }
    }
  },
  "response": {
    "status": 201,
    "bodyFileName": "payment-consents.json"
  }
}

mappings/payment-consents-error.json:

{
  "priority": 1,
  "request": {
    "method": "POST",
    "urlPath": "/middleware-nz-sandbox/v2.0/domestic-payment-consents",
    "headers": {
      "x-fapi-interaction-id": {
        "equalTo": "error"
      }
    }
  },
  "response": {
    "status": 500,
    "bodyFileName": "payment-consents-error.json"
  }
}

如果确实需要一条不检查 Header 的兜底规则,应给它设置更低的优先级。WireMock 的 priority 数字越小,优先级越高:

{
  "priority": 10,
  "request": {
    "method": "POST",
    "urlPath": "/middleware-nz-sandbox/v2.0/domestic-payment-consents"
  },
  "response": {
    "status": 400,
    "jsonBody": {
      "error": "Unsupported x-fapi-interaction-id"
    },
    "headers": {
      "Content-Type": "application/json"
    }
  }
}

如何确认 WireMock 实际加载了什么

先查询运行中实例的 mappings:

curl http://localhost:7070/__admin/mappings

然后在返回结果中搜索:

/middleware-nz-sandbox/v2.0/domestic-payment-consents

重点检查:

  • 是否存在返回 status.json 的旧 stub;
  • 两条 Header 规则是否已经加载;
  • 是否存在多份重复的 mapping;
  • 实际配置的 priority 是多少。

还可以查询未匹配或接近匹配的请求:

curl http://localhost:7070/__admin/requests/unmatched

如果可以在容器内执行只读检查,还应确认 mapping 文件确实挂载到了 WireMock 使用的文件根目录,而不是只存在于宿主机的另一个路径中。

Header 匹配本身的注意事项

Header 名称的大小写通常不会造成问题,因为 HTTP Header 名称不区分大小写。不过,equalTo 会对 Header 值进行精确匹配,所以下面的值并不等价:

error
Error
error 

如果需要忽略值的大小写,并且当前版本支持相应参数,可以使用:

"headers": {
  "x-fapi-interaction-id": {
    "equalTo": "error",
    "caseInsensitive": true
  }
}

不过,当前日志已经明确显示值为 [error],所以问题更可能出在 mapping 没有正确加载,或者存在重复的 stub,而不是 Header 值本身。

最直接的线索是 bodyFileName: "status.json"。先找到这条旧规则,将其删除、禁用或调低优先级,再确认两条 Header mapping 已经出现在 GET /__admin/mappings 的返回结果中。

备注:内容仅供参考。