Context.Redirect 是外部重定向,返回302状态码并设置Location头,触发浏览器发起新GET请求;非内部转发,不可保留原始method/body,且必须在响应未提交前调用。

Context.Redirect 会直接返回 302,不是内部转发
很多人误以为 Context.Redirect 是类似 Nginx 的内部重写(internal redirect),实际它只是设置 Location 响应头 + 返回 302 状态码,浏览器会发起**新的 GET 请求**到目标地址。如果你需要服务端内部跳转(不暴露新 URL、保留 method/body),Redirect 不适用,得换方案(比如手动调用对应 handler)。
正确调用 Context.Redirect 的参数和状态码
Redirect 方法签名是 c.Redirect(statusCode int, url string),第一个参数必须是 3xx 状态码,常见用法:
- 临时跳转:用
c.Redirect(302, "/login")—— 默认行为,浏览器可缓存但通常不缓存 - 永久跳转:用
c.Redirect(301, "https://example.com")—— 搜索引擎会更新索引,注意不可逆 - 307/308 用于保留原始请求方法(如 POST 跳转后仍为 POST),但浏览器支持度有限,且 Echo 不自动处理 body 重发,慎用
传入的 url 必须是完整路径(如 "/admin")或绝对 URL(如 "https://a.com/b");相对路径如 "../home" 会被原样塞进 Location 头,由浏览器解析,容易出错。
重定向前务必确保响应未提交
Echo 在调用 c.Redirect 时会检查 c.Response().Committed(),如果已经写入过 header 或 body(比如之前调用了 c.String、c.JSON 或甚至 c.Logger() 触发了默认 header 写入),就会 panic 报错:http: superfluous response.WriteHeader call。
Echo框架 5.1.0 版本源码包下载,适合关注 RealIP 行为变化、StartConfig.Listener、NewDefaultFS 和观测性中间件入口的开发团队。
典型踩坑场景:
- 在中间件里写了日志或设置了 header,再想重定向 → 提前 return 或用
c.Set("redirect_url", ...)延迟到最后统一处理 - 条件判断里先
c.JSON(200, ...),后面又加else { c.Redirect(...) }→ 逻辑顺序反了,重定向必须是 handler 中**唯一且最先**的响应操作
带查询参数或动态拼接 URL 时注意编码
如果重定向地址含用户输入(比如从 query 取 next 参数),直接拼接会导致 XSS 或 400 错误:
// ❌ 危险!未编码
c.Redirect(302, "/dashboard?from="+c.QueryParam("from"))
// ✅ 正确:用 url.URL + Query.Encode()
u := url.URL{Path: "/dashboard"}
q := u.Query()
q.Set("from", c.QueryParam("from"))
u.RawQuery = q.Encode()
c.Redirect(302, u.String())
另外,Echo 的 c.Request().URL 是解析后的对象,修改其 RawQuery 后需重新生成字符串,不能直接改 u.Path 后拼接 —— 那样会丢掉原有 query 或引发双重编码。
重定向看着简单,但状态码语义、响应时机、URL 安全性这三点,任何一个没对齐就容易在灰度或高并发时暴露问题。

















