Varnish 4升级至6.2.1后Accept请求的HTML/JSON响应异常问题
问题根因
Varnish 6.x相对Varnish 3.x调整了VCL钩子的执行时序和缓存匹配逻辑,原有代码失效主要有两个核心原因:
normalize子例程没有绑定到vcl_recv阶段执行,导致Accept头归一化逻辑没有在缓存匹配前触发,第一次请求时用原始Accept头去匹配缓存(找不到就回源),但回源后写入缓存的是归一化后的Accept头对应的响应,第二次请求匹配到缓存就正常了。- Varnish 6.x需要显式导入
std模块才能使用std.querysort方法,旧代码没有导入模块会导致部分逻辑执行失败。
修复方案
修正后适配Varnish 6.x的完整代码
# 显式导入std模块,Varnish 6.x强制要求 import std; sub vcl_recv { # 优先调用归一化逻辑,确保缓存匹配、回源前就完成Accept头处理 call normalize; } sub vcl_backend_response { # 成功从后端获取响应头后执行 if (!beresp.http.Vary) { # 无Vary头时直接添加 set beresp.http.Vary = "Accept"; } elseif (beresp.http.Vary !~ "Accept") { # 有Vary头但无Accept字段时追加 set beresp.http.Vary = beresp.http.Vary + ", Accept"; } } sub normalize { # 归一化Host头,移除端口号 set req.http.Host = regsub(req.http.Host, ":[0-9]+", ""); # 移除风险proxy头 unset req.http.proxy; # 归一化查询参数 set req.url = std.querysort(req.url); if (req.http.Accept) { if (req.http.Accept ~ "application/json") { set req.http.Accept = "application/json"; } else { set req.http.Accept = "text/html"; } } }
验证方式
配置修改后重新加载Varnish,清理现有缓存,连续发送携带Accept: application/json的请求,首次即可正常返回JSON内容,不会出现首次返回HTML的异常。
内容的提问来源于stack exchange,提问作者user966660
相关产品推荐
相关产品推荐

