在 Servlet 中请求转发的方法无非两种:
使用
RequestDispatcher
来调派请求使用
include()
来将另一个 Servlet 的操作流程包括至目前的操作流程中使用
forward()
方法将请求处理转发给其他的 Servlet
- 使用
HttpServletResponse
的sendRedirect()
方法要求浏览器重新请求另一个 URL
如果要调用 forward()
和 sendRedirect()
方法,那么目前的 Servlet 不能有任何响应确认,否则会抛出异常。
调用 forward()
方法时需要传入请求与响应对象,由于传递的是同一个 request,所以在转发过程中可以使用请求范围属性来传递一些属性。但 forward()
转发的这个动作是在 Web 容器中进行的,浏览器不知道请求被转发,地址栏也不会发生变化,转发也限制只能转发到服务器的另一个资源。而在整个转发过程中,都还是在同一个请求周期中。
当浏览器请求 Servlet1 后,Servlet1 将请求转发给了 Servlet2,之后 Servlet2 对浏览器进行响应,全程浏览器都不知道发送的请求已被转发。这样会存在的一个问题:当我刷新页面后,不过不加以处理会导致数据被重复提交。
比如现在有如下代码:
1 | <%"UTF-8" contentType="text/html; UTF-8" %> pageEncoding= |
1 | package xuac; |
提交表单后在输出了表单内容。
而当刷新一次后:
浏览器会提醒重复提交表单
当确认后发现内容被重复提交:
sendRedirect()
方法顾名思义,是重定向而非转发。可以让浏览器重新请求另一个 URL,请求的资源也可以是其他服务端的资源。与 forward()
不同,重定向实际上是两次请求,浏览器请求 Servlet1 时,Servlet1 将浏览器重定向到 Servlet2,然后浏览器向 Servlet2 发出请求,之后则由 Servlet2 做出响应或者其他的操作。这样的重定向浏览器是可以知道的,地址栏也会发生变化。
上面的例子中,解决刷新重复提交表单的方法之一就是使用重定向而不是转发(forward()
)。另一种方法是使用 token,通过它来判断是否是重复提交,进而进行处理。
由于在重定向的过程中,并没有使用同一个 HttpRequest
对象,所以想要传递属性只能通过 Session 来处理。而且因为是两次请求,需要额外的往返行为,所以相比 forward()
来说重定向会慢一些。
在上面的例子中我们也可以看到,调用 forward
或 sendRedirect
不会停止执行方法中的其余代码。所以如果转发和重定向之后还有可能会执行其他语句的话应该加上 return
。