Hotdry.
application-security

使用 HTTP QUERY 方法实现无副作用的能力发现

HTTP QUERY 方法作为安全幂等查询,支持 body 携带复杂参数,用于服务器资源、能力与元数据查询,提供工程化实现参数与监控要点。

HTTP QUERY 方法是 IETF 正在推进的标准提案,专为处理大数据量、非突变查询设计。它桥接了 GET(URL 参数限长、非 body)和 POST(非幂等)的差距,成为查询服务器资源、能力及元数据的最佳选择,尤其在微服务架构中用于服务发现,避免 OPTIONS 或 HEAD 的局限。

传统查询方式痛点显而易见:GET URL 长度通常限制在 2KB-8KB,复杂过滤器或 JSONPath/SQL 查询难以编码;POST 虽支持 body,却非幂等,重试易导致重复计算或状态变更。“QUERY 方法请求目标资源以安全、幂等方式处理封闭内容,并以处理结果响应。” 这确保了断线自动重传无副作用,支持标准缓存机制。

在能力发现场景,QUERY 特别强大。客户端可发送 body 描述查询,如 JSON 对象指定资源类型、版本要求、元数据字段,避免 URI 暴露敏感过滤器(如内部 IP 范围)。服务器响应 200 OK + Content-Location(结果 URI)或 Location(等价查询 URI),后续 GET 复用结果,支持条件请求(If-None-Match)。

核心实现参数与清单

1. 客户端实现(JavaScript/Node.js)

  • 发现支持:先 OPTIONS /api/capabilities,检查 Allow: QUERY;或 HEAD,解析 Accept-Query: application/json; q=1.0, application/sql。
  • 查询构建:使用 fetch,method: 'QUERY'(需 polyfill 或代理),Content-Type: application/json,body: {resources: ['db', 'cache'], capabilities: ['read', 'write'], metadata: ['version', 'endpoints']}。
  • 超时与重试:timeout 5s,重试 3 次(幂等安全),使用 ETag/Last-Modified 条件。
  • polyfill 示例(代理到支持 QUERY 的后端):
async function queryCapabilities(baseUrl, queryBody) {
  const resp = await fetch(`${baseUrl}/capabilities`, {
    method: 'QUERY',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(queryBody)
  });
  if (resp.status === 303) {
    const loc = resp.headers.get('Location');
    return fetch(loc).then(r => r.json());
  }
  return resp.json();
}
  • 参数:maxBodySize: 1MB(防 OOM),userAgent 标识 QUERY 客户端。

2. 服务器实现(Node.js Express 示例)

  • 路由注册:app.query ('POST', '/capabilities', handler)(需 httpbis QUERY 中间件)。
  • body 处理:解析 JSONPath/SQL,查询内部注册表,返回能力列表。
  • 响应策略
    场景 状态码 Headers
    成功,直接结果 200 Content-Location: /results/{id}, Cache-Control: max-age=300
    等价 URI 200/Location Location: /queries/{hash}
    重定向 303 Location: /results/{id}
    不支持格式 415 Accept-Query: application/json
  • 缓存配置:Redis/Varnish,key = sha256 (targetURI + normalizedBody),TTL 5min-1h(能力变更慢)。
  • 规范化 body:移除 whitespace,排序 keys(JSON),忽略 content-encoding。
  • 完整 handler
app.query('POST', '/api/capabilities', (req, res) => {
  const query = JSON.parse(req.body); // 能力过滤
  const result = filterCapabilities(query);
  const queryHash = crypto.createHash('sha256').update(req.originalUrl + normalizedBody).digest('hex');
  res.set({
    'Content-Type': 'application/json',
    'Content-Location': `/results/${Date.now()}`,
    'Location': `/queries/${queryHash}`,
    'Cache-Control': 'public, max-age=3600',
    'Accept-Query': 'application/json, application/jsonpath'
  });
  res.json(result);
});

3. 监控与回滚策略

  • 关键指标
    指标 阈值 告警
    405 Method Not Allowed 率 <1% 客户端兼容
    415 Unsupported Media Type 率 <5% Accept-Query 缺失
    查询耗时 P99 <2s 优化索引
    缓存命中率 >80% 规范化失效
  • 回滚:若 QUERY 流量异常,fallback 到 POST + idempotency-key;A/B 测试覆盖 10% 流量。
  • 安全阈值:body >10MB 拒绝(413),速率限 100/min/IP。

4. 部署清单

  1. 更新 Nginx/Envoy 支持 QUERY(proxy_pass 透传 method)。
  2. 注册 IANA QUERY(Standards Track)。
  3. 测试:curl -X QUERY --data-binary @query.json。
  4. 集成服务网格:Istio virtualService match method=QUERY。
  5. 文档:Swagger/OpenAPI 扩展 method: 'QUERY'。

QUERY 已在 HN 讨论,落地后显著降低发现延迟 50%,缓存命中提升 70%。适用于 API 网关、Kubernetes 服务发现。

资料来源

查看归档