拓冰建站拓冰建站
首页 / 资讯中心 / 正文

PostgREST Vary 响应头解析:缓存代理/CDN 协作与 response.headers GUC 覆盖机制

PostgREST Vary 响应头解析缓存代理/CDN 协作与 response.headers GUC 覆盖机制【免费下载链接】postgrestREST API for any Postgres database项目地址: https://gitcode.com/GitHub_Trending/po/postgrestPostgREST 默认会在每个 HTTP 响应中附带值为Accept, Prefer, Range的Vary响应头用于告知缓存代理与 CDN 哪些请求头会改变响应内容从而避免缓存串扰。本篇指南以 docs/references/api/vary_header.rst 为主线讲解该默认头的来源、覆盖方式response.headersGUC 变量以及背后的源码实现与注意事项读完即可在自己的 PostgREST 部署中正确地定制缓存相关响应头。为什么 PostgREST 要发送 Vary 头Vary是 HTTP 协议中用于协商缓存键cache key的标准响应头。它告诉中间缓存如 CDN、反向代理以及浏览器缓存响应的内容会随请求中列出的请求头不同而不同因此缓存时必须把这些请求头的值一并纳入缓存键计算。PostgREST 返回的资源表示取决于三个请求头因此默认在响应中固定输出Vary: Accept, Prefer, RangeAccept客户端通过 Accept 协商响应媒体类型JSON、OpenAPI、CSV 等自定义媒体类型Prefer客户端通过 Prefer 请求头控制返回表示如Prefer: countexact、Prefer: returnrepresentation等Range客户端通过 Range 请求头做分页范围请求。PostgREST 官方认为这一组合should fit most of the bills满足大多数场景即对该三个请求头的任一变体缓存代理都应区分缓存。默认行为不要求任何配置开箱即用。默认 Vary 头的源码实现默认 Vary 头并非配置项而是代码内置的固定响应头。在 src/library/PostgREST/App.hs 的toWaiResponse中可以看到完整逻辑toWaiResponse timing warnMsgs (Response.PgrstResponse st hdrs bod) Wai.responseLBS st (hdrs serverTimingHeaders timing warningHeaders warnMsgs [varyHeader | not $ varyHeaderPresent hdrs]) bod varyHeader :: HTTP.Header varyHeader (hVary, Accept, Prefer, Range) varyHeaderPresent :: [HTTP.Header] - Bool varyHeaderPresent any (\(h, _v) - h hVary)这段代码揭示了两个关键实现事实默认 Vary 头是**追加append**在响应头列表末尾的而不是覆盖追加前会先检查响应头列表中是否已存在VaryvaryHeaderPresent按头名匹配值不参与比较。只要响应中已经存在任意一个 Vary 头PostgREST 就不再追加默认值。后一点正是原文档所说available for override的机制基础——通过response.headers设置自定义 Vary 后内置默认值会自动让位。用 response.headers GUC 覆盖 Vary 头PostgREST 暴露了一组用于定制 HTTP 响应的 GUCGrand Unified Configuration变量response.headers是其中之一。在数据库函数内部可以通过set_config把它设置为一个JSON 数组数组中的每个元素是单键对象即一个响应头-- Override the Vary header to include Accept, Prefer and X-Test-Vary headers perform set_config(response.headers, [{Vary: Accept, Prefer, X-Test-Vary}], true);执行上述语句后PostgREST 会原样使用use provided value verbatim这个 Vary 值即响应头变为Vary: Accept, Prefer, X-Test-Varyset_config的第三个参数传true表示is_local即该设置只在当前事务内生效事务结束自动还原——这与 PostgREST 的每请求一个事务模型见 docs/references/transactions.rst配合良好适合放在被调用的存储函数中使用。为什么必须是数组 单键对象response.headers的取值有严格结构约束必须是单键对象的数组而不能是单个多键对象。原因在于像Cache-Control、Set-Cookie这类头需要重复出现才能携带多个值而 JSON 对象无法表达重复键。这一约束在源码中有直接印证。响应头 GUC 的解析器位于 src/library/PostgREST/Response/GucHeader.hsinstance JSON.FromJSON GucHeader where parseJSON (JSON.Object o) case KM.toList o of [(k, JSON.String s)] - pure $ GucHeader (CI.mk $ toUtf8 $ K.toText k, toUtf8 s) _ - mzero parseJSON _ mzero可见每个 JSON 对象必须恰好有一个键值对KM.toList o解构后是[(k, s)]单元素列表且值必须是字符串对象为空、含多个键或非字符串值都会解析失败。头名会被转为大小写不敏感CI即 CaseInsensitive的字节串这也解释了为什么覆盖时Vary头名大小写不影响匹配。事务作用域与典型用法response.headers必须在产生该请求响应的同一事务内设置。PostgREST 将每个请求包装在事务中执行因此最常见的做法是在被调用的数据库函数内部设置create or replace function get_items() returns json as $$ perform set_config(response.headers, [{Vary: Accept, Prefer, X-Test-Vary}], true); return (select coalesce(json_agg(row_to_json(t)), []) from items t); $$ language plpgsql;在数据库端如ALTER ROLE或postgrest.conf的db-pre-request钩子全局设置response.headers同样可行但需注意其作用范围与事务边界避免对不需要的响应也施加自定义 Vary。覆盖范围与注意事项可覆盖的头部范围response.headers并不只用于 Vary。如 docs/references/transactions.rst 所述PostgREST 提供的Content-Type、Location等头部均可通过该 GUC 覆盖。例如向客户端下发缓存指令-- tell client to cache response for two days SELECT set_config(response.headers, [{Cache-Control: public}, {Cache-Control: max-age259200}], true);需要特别注意的是即使覆盖了Content-Type响应体仍会被转换为 JSON除非配合自定义媒体类型处理见 docs/references/api/media_type_handlers.rst 与 docs/how-tos/providing-images-for-img.rst 中的实际用法。与缓存语义相关的建议修改 Vary 头属于影响缓存键的操作应谨慎为之扩展 Vary 值如在默认值上追加X-Test-Vary会让缓存为更多请求头变体分别保存副本可能增大缓存占用但能保证正确性收窄或替换 Vary 值可能造成不同表示的响应被混用需要确保缓存代理确实了解并区分所依赖的请求头默认值Accept, Prefer, Range之外若你的 API 通过其他请求头如自定义鉴权头、Accept-Profile等影响响应内容应将这些头一并加入 Vary否则中间缓存可能返回错误表示。与 CORS 的交互需要注意的是PostgREST 的 CORS 策略实现src/library/PostgREST/Cors.hs中corsVaryOrigin被设置为False即 CORS 中间件默认不向 Vary 追加Origin。若你的部署同时使用 CDN 且按 Origin 区分响应如 CORS 允许列表配置不同应在自定义 Vary 中显式考虑Origin避免跨域缓存串扰。错误排查PGRST111如果response.headers的 JSON 结构不符合单键对象数组的约束例如写成单个对象、多键对象或非字符串值PostgREST 会返回 500 错误错误码为PGRST111An invalidresponse.headerswas set见 docs/references/errors.rst。遇到该错误时优先检查外层是否为 JSON 数组[...]每个元素是否为单键对象{Header-Name: value}值是否为字符串JSON 字符串字面量须转义内部引号。小结PostgREST 对Vary头的处理体现了合理默认 显式覆盖的设计默认输出Vary: Accept, Prefer, Range由 src/library/PostgREST/App.hs 内置并在检测到已有 Vary 头时自动跳过通过事务内的set_config(response.headers, ...)可完全接管 Vary 的取值原样输出取值必须为单键对象数组解析细节见 src/library/PostgREST/Response/GucHeader.hs非法结构会触发 PGRST111 错误。对于任何位于 CDN 或反向代理之后的 PostgREST 服务理解并合理定制 Vary 头是保证缓存正确性的前提而response.headersGUC 提供了无需改代码、纯 SQL 即可完成的定制入口。【免费下载链接】postgrestREST API for any Postgres database项目地址: https://gitcode.com/GitHub_Trending/po/postgrest创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门