同一批JSON有时成功、有时返回400 Decoding error,客户端本地解析也没问题。这种偶发性要优先怀疑传输层:请求体被截断、gzip标头与实际内容不一致,或API网关解压后仍把Content-Encoding:gzip传给Magento。

保存一份失败请求的原始证据

在客户端记录请求ID、Content-Length、Content-Encoding和请求体SHA-256,不要记录Token和客户隐私。服务端按同一请求ID记录接收到的字节数与哈希。两端哈希不同,问题发生在代理链。

sha256sum payload.json
curl -v --data-binary @payload.json \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer ***' \
  https://example.com/rest/V1/your/endpoint

gzip请求要么完整支持,要么关闭

HTTP响应gzip很常见,但压缩请求体并非所有Nginx和PHP组合都会自动处理。如果网关已解压请求体,必须移除或改写Content-Encoding;否则下游会对普通JSON再解压一次并失败。先用未压缩data-binary请求建立基线。

检查大小限制与超时

nginx -T | grep -E 'client_max_body_size|client_body_timeout|proxy_request_buffering'
php -i | grep -E 'post_max_size|max_input_time'

超限常返回413,但自定义网关可能统一映射成400。比较失败请求大小是否集中在某个阈值,查看Nginx error log有没有client intended to send too large body或upstream prematurely closed。

JSON本身也要按字节验证

  • Content-Type明确为application/json并使用UTF-8;
  • 去掉UTF-8 BOM和不可见控制字符;
  • 金额用数字或约定字符串,不使用NaN或Infinity;
  • 不要用普通表单编码发送JSON;
  • PHP端读取php://input一次后不要让插件再次读取空流。

最终在相同代理链连续发送多种大小的固定payload并核对哈希。修好后错误率应归零,而不是因为重试掩盖偶发失败。