You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Envoy前端代理401状态下如何仅对单个域名而非全域名执行重定向

问题解答

1. SNI获取失败原因及正确实现

你当前使用的v1.16.2版本Envoy不支持requestedServerName() API,这个接口是v1.17.0版本才正式加入的,所以调用返回空属于版本兼容问题。如果要使用SNI匹配方案,需要先将Envoy镜像升级到envoyproxy/envoy:v1.17.0及以上版本。
另外你原有代码存在变量作用域错误:SNI是envoy_on_request函数内的局部变量,envoy_on_response函数无法直接访问,需要将值存入动态元数据跨阶段传递,正确写法如下:

inline_code: |
  function envoy_on_request(request_handle)
    -- 将SNI存入动态元数据,供response阶段读取
    local sni = request_handle:streamInfo():requestedServerName()
    request_handle:streamInfo():dynamicMetadata():set("envoy.lua", "request_sni", sni)
  end

  function envoy_on_response(response_handle)
    local sni = response_handle:streamInfo():dynamicMetadata():get("envoy.lua")["request_sni"]
    local match_domain = "app.domain.tld"
    if response_handle:headers():get(":status") == "401" and sni == match_domain then
      response_handle:headers():replace(":status", "301")
      response_handle:headers():replace("location", "https://login.domain.tld")
    end
  end

2. 无需升级的替代方案(推荐)

如果不想升级Envoy版本,完全不需要依赖SNI匹配,直接读取HTTP请求的:authority伪头(即Host头)即可拿到访问域名,兼容所有支持Lua过滤器的Envoy版本,代码更简洁:

inline_code: |
  function envoy_on_response(response_handle)
    local host = response_handle:headers():get(":authority")
    local match_domain = "app.domain.tld"
    -- 如需匹配带端口的域名,可修改判断条件为host == "app.domain.tld:3000"
    if response_handle:headers():get(":status") == "401" and host == match_domain then
      response_handle:headers():replace(":status", "301")
      response_handle:headers():replace("location", "https://login.domain.tld")
    end
  end

该方案不需要新增任何额外过滤器,完全基于现有Lua过滤器即可实现,也避免了非TLS场景下SNI为空的问题。如果后续需要扩展规则,比如排除所有api开头的子域名,直接新增not string.find(host, "^api%-.*%.domain%.tld")判断条件即可。

内容的提问来源于stack exchange,提问作者niolm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 19:57:02