Servlet 网页重定向
sendRedirect 与 forward 的本质差别、301 与 302 的选择。
Key Points重定向是客户端行为,浏览器发第二次请求,地址栏会变;转发是服务端行为,一次请求,地址栏不变。
两种跳转
| forward | ||
|---|---|---|
| Where | 客户端 | 服务端 |
| Requests | 2 次 | 1 次 |
| URL bar | 变成新地址 | 不变 |
| Request scope | 丢失 | 保留 |
| Target | 可以是外部站点 | 只能本应用内 |
| Speed | 多一次往返 | 快 |
代码
Java
// 重定向:登录成功后跳到首页
resp.sendRedirect(req.getContextPath() + "/home");
// 转发:Servlet 查完数据交给 JSP 渲染
req.setAttribute("user", user);
req.getRequestDispatcher("/WEB-INF/views/user.jsp").forward(req, resp);Redirect URLs must include getContextPath(), or a /myapp deployment jumps to the server root. Forwards use app-relative paths without the context path.
301 与 302
Java
// 302 临时重定向(sendRedirect 的默认行为)
resp.setStatus(HttpServletResponse.SC_FOUND);
resp.setHeader("Location", "/new-page");
// 301 永久重定向:告诉搜索引擎和浏览器缓存这个跳转
resp.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
resp.setHeader("Location", "/new-page");
// 307 临时重定向,且保持原请求方法(POST 仍是 POST)
resp.setStatus(HttpServletResponse.SC_TEMPORARY_REDIRECT);
resp.setHeader("Location", "/new-page");- 301 —— 网站改版、域名迁移。浏览器会长期缓存,改错了很难撤回
- 302 —— 登录后跳转、临时维护。默认选择
- 307 —— 需要保留 POST 体和方法的场景
POST 后重定向
After a successful form submit, redirect to the result page instead of forwarding to it. Otherwise refreshing resubmits the form — that is the PRG (Post/Redirect/Get) pattern.
Java
// 错误:刷新会重复下单
req.getRequestDispatcher("/order/success.jsp").forward(req, resp);
// 正确:重定向,刷新只是重新 GET 结果页
resp.sendRedirect(req.getContextPath() + "/order/success?id=" + orderId);Always
return after sendRedirect. It does not stop method execution; later code still runs and may write a partial response, causing IllegalStateException.两种跳转
| sendRedirect | forward | |
|---|---|---|
| 发生位置 | 客户端 | 服务端 |
| 请求次数 | 2 次 | 1 次 |
| 地址栏 | 变成新地址 | 不变 |
| request 域 | 丢失 | 保留 |
| 目标范围 | 可以是外部站点 | 只能本应用内 |
| 性能 | 多一次往返 | 快 |
代码
Java
// 重定向:登录成功后跳到首页
resp.sendRedirect(req.getContextPath() + "/home");
// 转发:Servlet 查完数据交给 JSP 渲染
req.setAttribute("user", user);
req.getRequestDispatcher("/WEB-INF/views/user.jsp").forward(req, resp);重定向的 URL 要自己加 getContextPath(),否则在 /myapp 部署下会跳到根路径。转发用应用内路径,不需要 context path。
301 与 302
Java
// 302 临时重定向(sendRedirect 的默认行为)
resp.setStatus(HttpServletResponse.SC_FOUND);
resp.setHeader("Location", "/new-page");
// 301 永久重定向:告诉搜索引擎和浏览器缓存这个跳转
resp.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
resp.setHeader("Location", "/new-page");
// 307 临时重定向,且保持原请求方法(POST 仍是 POST)
resp.setStatus(HttpServletResponse.SC_TEMPORARY_REDIRECT);
resp.setHeader("Location", "/new-page");- 301 —— 网站改版、域名迁移。浏览器会长期缓存,改错了很难撤回
- 302 —— 登录后跳转、临时维护。默认选择
- 307 —— 需要保留 POST 体和方法的场景
POST 后重定向
表单提交成功后应该重定向到结果页,而不是直接 forward 到结果页。否则用户刷新页面会重复提交表单——这就是 PRG(Post/Redirect/Get)模式。
Java
// 错误:刷新会重复下单
req.getRequestDispatcher("/order/success.jsp").forward(req, resp);
// 正确:重定向,刷新只是重新 GET 结果页
resp.sendRedirect(req.getContextPath() + "/order/success?id=" + orderId);sendRedirect 之后必须 return。它不会终止方法执行,后面的代码照样跑,可能已经写了一半响应导致 IllegalStateException。