Servlet转发响应呼叫者/上一页

时间:2012-08-17 21:58:09

标签: java java-ee servlets servlet-3.0

我正在尝试将servlet响应转发到它来自同一页面(a.k.a:上一页,或“servlet”调用者)。

我看过很多答案(例如thisthis),但仍然无法使其发挥作用。

我通常会执行以下操作将servlet的响应重定向到另一个页面:

request.getRequestDispatcher("MyNewPage").forward(request, response);

但是我试图将“MyNewPage”改为其他我认为解决方案的选项:

request.getRequestDispatcher((String)request.getAttribute("javax.servlet.forward.request_uri")).forward(request, response);
request.getRequestDispatcher(request.getHeader("referer")).forward(request, response);

和其他选项,无法使其发挥作用。

我做错了什么?

2 个答案:

答案 0 :(得分:17)

首先,request.getHeader("referer")会返回一个完整的网址,但您必须删除http://server[:port]/,因为您传递给request.getRequestDispatcher()的内容会添加到应用程序上下文中,如下所示:

/NameOfApp/http:/localhost:8084/NameOfApp/test.jsp

这不是您想要的,因为您只需将以下内容传递给调度程序方法:

test.jsp

如果我们从一开始就采取措施,第一个请求就从这个URL开始:

http://localhost:8084/RequestDispatcher/test.jsp

正向工作,但是第二次你向Servlet提出请求时,Servlet会转发给自己。所以你将进入一个Servlet调用自己的循环。为什么会这样?由于您从表单调用Servlet,这意味着在第一次请求后,浏览器地址框中的URL地址将更改为Servlet的URL地址。

http://localhost:8084/RequestDispatcher/NewServlet

Servlet会将请求转发回JSP页面,浏览器只会显示,但浏览器地址框中的URL仍然是包含Servlet而不是JSP页面的URL:

http://localhost:8084/RequestDispatcher/NewServlet

因此,下次您点击提交时,Servlet会尝试将请求转发给自己。如果我是你,我会使用重定向。这似乎更适合您的目的:

response.sendRedirect(request.getHeader("referer"));

这将始终更改浏览器地址框中的URL并防止Servlet循环。这会对请求参数产生影响,但您始终可以在重定向URL上添加它们(如果它不是敏感信息)或将它们存储在会话中,直到您在下一个第一次请求时检索它们,这将是重定向。

像JSF这样的框架可以帮助您避免这些问题。

允许您使用forward的最简单的解决方案是保留JSP(viewid)的形式中的隐藏参数,该JSP调用Servlet而不是使用request.getHeader(“referer”)。您需要检查循环,因为有人可能故意更改值以强制您的Servlet容器循环并最终导致VM崩溃。但是你可以使用一个请求属性来记录链中的先前请求,如果它是相同的,你会回复一个错误。因此,在servlet中,您将使用隐藏字段值来决定转发到的位置:

request.getRequestDispatcher(request.getParameter("viewid")).forward(request, response);

并在您的JSP中:

<input type="hidden" name="viewid" value="test.jsp">

我认为这可以满足您的要求。

答案 1 :(得分:0)

更好的策略是在请求中添加调用者属性。因此,在处理后,被调用者servlet可以将其请求转发回调用者。

类似的东西,

<强>呼叫者

request.setAttribute("caller", "/page/Foo.jsp");

<强>被叫方

String uri = (String)request.getAttribute("caller");
getServletContext().getRequestDispatcher(uri).forward(request, response);

或者您可以尝试在会话中添加呼叫者并在转发后将其删除。