
后端API网关微服务【免费下载链接】fabioConsul Load-Balancing made simple项目地址https://gitcode.com/gh_mirrors/fa/fabio点击查看免费下载fabioConsul Load-Balancing made simple为每个路由目标提供了redirectcode选项可以在不修改后端服务的前提下让进入的 HTTP 请求直接以指定 3xx 状态码跳转到任意目标 URL。本文基于仓库文档与源码完整讲解 redirect 选项的语法、状态码约束、$path/$host伪变量的展开规则、HTTP→HTTPS 跳转的配置要点并结合源码与测试用例说明其底层实现原理帮助你快速落地 301/302/303 等各类重定向场景。一、核心机制redirect 选项与 3xx 状态码校验redirectcode是 fabio 路由目标Target上的一个选项opts。code是重定向响应的 HTTP 状态码必须位于 300–399 之间否则路由无效。从源码看该选项在 route/route.go 的目标解析阶段被处理if opts[redirect] ! { t.RedirectCode, err strconv.Atoi(opts[redirect]) if err ! nil { log.Printf([ERROR] redirect status code should be numeric in 3xx range. Got: %s, opts[redirect]) } else if t.RedirectCode 300 || t.RedirectCode 399 { t.RedirectCode 0 log.Printf([ERROR] redirect status code should be in 3xx range. Got: %s, opts[redirect]) } }也就是说fabio 对 redirect 值做了两层校验校验内容结果必须是纯数字字符串strconv.Atoi可解析否则输出错误日志RedirectCode保持为 0不重定向数值必须落在[300, 399]闭区间否则RedirectCode被强制重置为 0路由退化为普通代理对应的结构体字段定义在 route/target.go// RedirectCode is the HTTP status code used for redirects. // When set to a value 0 the client is redirected to the target url. RedirectCode int当RedirectCode 0时目标即被标记为“重定向目标”请求不会再被转发到上游而是直接返回跳转响应。二、配置方式一route add 命令通过动态路由命令route add为服务添加重定向目标。目标 URL 写在命令中opts里携带redirectcode# 将 /path 重定向到 https://www.google.com/ route add svc /path https://www.google.com/ opts redirect301这条命令的完整语法格式见 route/parse_new.go 中内嵌的命令文档为route add svc src dst[ weight w][ tags t1,t2,...][ opts k1v1 k2v2 ...]其中opts支持多个键值对用空格分隔例如route add svc /old https://new.example.com/ opts redirect301 strip/old三、配置方式二urlprefix- 服务标签在使用 Consul 等注册中心时fabio 通过服务的urlprefix-标签自动生成路由。此时重定向目标 URL 必须写在状态码之后因为标签本身表达的是“注册该标签的服务地址”而不是重定向目标urlprefix-/path redirect301,https://www.google.com/标签的构成规则可以理解为urlprefix-匹配前缀 optionvalue,重定向目标URL匹配前缀决定哪些请求命中该路由如/pathredirect301跳转状态码逗号后的https://www.google.com/完整的重定向目标 URL。四、$path 伪变量保留原始请求路径重定向目标通常需要保留客户端请求的原始 URI。在目标 URL 末尾追加$path伪变量即可实现urlprefix-/path redirect303,https://www.foo.com$path$path会被替换为当前请求的完整路径含查询参数。BuildRedirectURL的实现位于 route/target.go其展开逻辑相当精细func (t *Target) BuildRedirectURL(requestURL *url.URL) { t.RedirectURL url.URL{ Scheme: t.URL.Scheme, Host: t.URL.Host, Path: t.URL.Path, RawPath: t.URL.Path, RawQuery: t.URL.RawQuery, } // treat case of $path not separated with a / from host if strings.HasSuffix(t.RedirectURL.Host, $path) { t.RedirectURL.Host t.RedirectURL.Host[:len(t.RedirectURL.Host)-len($path)] t.RedirectURL.Path $path } // remove / before $path in redirect url if strings.Contains(t.RedirectURL.Path, /$path) { t.RedirectURL.Path strings.Replace(t.RedirectURL.Path, /$path, $path, 1) t.RedirectURL.RawPath strings.Replace(t.RedirectURL.RawPath, /$path, $path, 1) } // remove strip path, insert passed request path, set query if strings.Contains(t.RedirectURL.Path, $path) { replacePath : requestURL.Path var replaceRawPath string if requestURL.RawPath { replaceRawPath requestURL.Path } else { replaceRawPath requestURL.RawPath } // strip path before replacement if t.StripPath ! { replacePath strings.TrimPrefix(replacePath, t.StripPath) replaceRawPath strings.TrimPrefix(replaceRawPath, t.StripPath) } // add prepend path if t.PrependPath ! { replacePath t.PrependPath replacePath replaceRawPath t.PrependPath replaceRawPath } // do path replacement t.RedirectURL.Path strings.Replace(t.RedirectURL.Path, $path, replacePath, 1) t.RedirectURL.RawPath strings.Replace(t.RedirectURL.RawPath, $path, replaceRawPath, 1) // set query if t.RedirectURL.RawQuery requestURL.RawQuery ! { t.RedirectURL.RawQuery requestURL.RawQuery } } if t.RedirectURL.Path { t.RedirectURL.Path / } t.RedirectURL.Host strings.Replace(t.RedirectURL.Host, $host, requestURL.Host, 1) }几个值得注意的细节$path前可带/也可不带https://www.foo.com$path与https://www.foo.com/$path效果等价源码会先移除/$path中的斜杠再做替换避免生成//双斜杠请求查询参数自动继承当目标 URL 自身没有 RawQuery 而请求带查询串时查询串会被追加到重定向目标上如请求/?aaa1会得到http://bar.com/?aaa1URL 编码保留替换时同时处理Path与RawPath编码字符如%20、%2f会原样保留见 route/target_test.go 中的测试用例空路径兜底如果最终 Path 为空统一补为/保证重定向目标永远是一个合法绝对 URL。$path 展开行为对照表以下行为均由 route/target_test.go 中的表驱动测试逐一验证路由定义请求路径重定向结果route add svc / http://bar.com/$path/abchttp://bar.com/abcroute add svc / http://bar.com/bbb/$path/a/b/chttp://bar.com/bbb/a/b/croute add svc / http://bar.com/bbb$path/a/b/chttp://bar.com/bbb/a/b/croute add svc / http://bar.com/$path/?aaa1http://bar.com/?aaa1route add svc / http://bar.com/$path/%20http://bar.com/%20route add svc /stripme http://bar.com/$path opts strip/stripme/stripme/abchttp://bar.com/abcroute add svc / http://bar.com/$path opts prepend/prefix/abchttp://bar.com/prefix/abc五、$host 伪变量与 HTTP→HTTPS 强制跳转$host伪变量会替换为当前请求的 Host。最典型的用法是把 HTTP 80 端口的流量统一跳到 HTTPS 对应主机例如 route/table_test.go 中的“典型 HTTPS 跳转”配置route add my-service example.com:80/ https://example.com$path opts redirect301而要让$host生效把任意主机名的请求跳到同名 HTTPS 地址需要使用通配主机*route add redirect *:80/ https://$host/$path请求http://foo.com/abc会被跳转到https://foo.com/abc。若只保留主机、不保留路径则写为route add redirect *:80/ https://$host/$host的替换发生在BuildRedirectURL的最后一行route/target.go。关键前提来自原文档要从 HTTP 跳到 HTTPS路由的 src 必须包含 HTTP 端点的host:port即example.com:80/或*:80/这样的写法这样 fabio 才能在 80 端口监听并匹配到 HTTP 请求否则无法触发跳转。同理若在 8080 端口提供 HTTP 服务应写为*:8080/。组合使用$host与$path的完整跳转见 route/target_test.goroute add redirect *:80/ https://$host/$path请求重定向结果http://foo.com/https://foo.com/http://foo.com/abchttps://foo.com/abchttp://foo.com/abc/?aaa1https://foo.com/abc/?aaa1六、与 strip / prepend 选项的协同重定向路径替换发生在 strip 与 prepend 处理之后见 route/target.go因此$path展开的值是“先剥离前缀、再附加前缀”后的结果。这正是 GitHub issue #824 所修复的行为route/target_test.goroute add svc *:80/stripme https://bar.com/bbb$path opts strip/stripme请求路径重定向结果/stripme/abchttps://bar.com/bbb/abc/stripme/?aaa1https://bar.com/bbb/?aaa1如果同一目标同时配置strip与prepend则先 strip 后 prependroute add svc / http://bar.com/$path opts prepend/prefix strip/stripme请求/stripme/abc将得到http://bar.com/prefix/abc。七、底层实现重定向如何被触发重定向目标确定后整个请求处理流程如下路由查找proxy/http_proxy.go 通过p.Lookup(r)找到命中的 Target若未命中则返回NoRouteStatus配置的状态码默认 404与 noroute HTML重定向 URL 预生成route/table.go 在请求到达时调用target.BuildRedirectURL(req.URL)生成并缓存重定向 URL——这正是 route/target.go 注释“This is cached here to prevent multiple generations per request”的含义避免每个请求重复生成响应返回proxy/http_proxy.go 检查t.RedirectCode ! 0 t.RedirectURL ! nil命中后调用标准库http.Redirect(w, r, t.RedirectURL.String(), t.RedirectCode)返回 3xx 响应不再向任何上游发起请求if t.RedirectCode ! 0 t.RedirectURL ! nil { http.Redirect(w, r, t.RedirectURL.String(), t.RedirectCode) if p.Stats.RedirectCounter ! nil { p.Stats.RedirectCounter.With(code, strconv.Itoa(t.RedirectCode)).Add(1) } return }指标统计每次重定向都会累加RedirectCounter指标并按状态码打标签code301等可接入 fabio 的 Prometheus/StatsD 等监控体系见 metrics 目录。八、状态码选型建议与注意事项301 Moved Permanently永久性迁移浏览器与搜索引擎会缓存新地址适合域名/路径永久变更、HTTP→HTTPS 全局升级302 Found临时性跳转适合 A/B 测试、临时维护页303 See Other语义上明确“请用 GET 重新请求”适合原文档示例中的表单提交后跳转场景307/308保留请求方法与请求体适合需要保持 POST 语义的跳转。配置时请记住原文档强调的两条硬性约束redirect的值必须是 300–399 之间的数字否则目标上的RedirectCode会被置 0请求将按普通代理转发而非重定向错误信息会打到日志中使用urlprefix-标签时重定向目标 URL 必须写在状态码之后redirect301,https://...因为标签默认把“服务注册地址”当作目标。九、相关参考原始文档docs/content/feature/http-redirects.mdredirect 解析与状态码校验route/route.go重定向 URL 生成与$path/$host展开route/target.go重定向触发与指标统计proxy/http_proxy.go重定向 URL 缓存route/table.go行为测试矩阵route/target_test.go、route/table_test.go路由命令完整语法route/parse_new.go赞分享后端API网关微服务【免费下载链接】fabioConsul Load-Balancing made simple项目地址https://gitcode.com/gh_mirrors/fa/fabio点击查看免费下载相关推荐Apache APISIX redirect 插件完全指南URI 重定向与 HTTP 跳转 HTTPS 的配置实战Apache APISIX redirect 插件完全指南URI 重定向与 HTTP 跳转 HTTPS 的配置实战 redirect 是 Apache API后端微服务云原生go_router 重定向Redirection完全指南基于应用状态的路由跳转、顶层与路由级重定向及 redirectLimit 限制go_router 重定向Redirection完全指南基于应用状态的路由跳转、顶层与路由级重定向及 redirectLimit 限制 导读 重定向Re跨平台移动开发UI组件开发工具Apache APISIX redirect 插件详解URI 重定向、HTTP 强制跳转 HTTPS 与查询字符串保留实战Apache APISIX redirect 插件详解URI 重定向、HTTP 强制跳转 HTTPS 与查询字符串保留实战 导读 本文聚焦 Apache AP后端微服务云原生创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考