4. request实现请求转发
请求转发指一个web资源收到客户端请求后,通知服务器去调用灵位一个web资源进行处理。
request对象提供了一个getRequestDispatcher方法,该方法返回一个RequestDispatcher对象,调用这个对象的forword方法可以实现请求转发。
request对象同时也是一个域对象,开发人员可以通过request对象在实现转发时,把数据通过request对象带给其他web资源处理。
- setAttribute方法
- getAttribute方法
- getAttributeNames方法
- removeAttribute方法
4.1 实现请求转发
访问HttpServletRequestDemo5,使用request将其转发到HttpServletRequestDemo6中,并在request中传递参数:
1 /**
2 * request实现请求转发,并传递数据
3 */
4 @WebServlet(name = "HttpServletRequestDemo5")
5 public class HttpServletRequestDemo5 extends HttpServlet {
6
7 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
8 request.setAttribute("name", "bear");
9 request.getRequestDispatcher("/HttpServletRequestDemo6").forward(request, response);
10 } 11 }
1 /**
2 * 获取request中存储的数据
3 */
4 @WebServlet(name = "HttpServletRequestDemo6")
5 public class HttpServletRequestDemo6 extends HttpServlet {
6
7 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
8 response.getWriter().write((String)request.getAttribute("name"));
9 }
10 }
运行结果:
ServletContext对象也可实现请求转发(JavaWeb学习笔记(八)--ServletConfig和ServletContext对象介绍):
this.getServletContext().getRequestDispatcher("/HttpServletRequestDemo6").forward(request, response);
4.2 转发时需要注意的细节:
如果在调用forward方法之前,在Servlet程序中写入部分内容已经被真正的传送到了客户端,forword方法将抛出IllegalStateException异常:
例如,如下两种方式都会抛异常,所以最好在每个跳转后最好加上return语句:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); out.write("aaaa"); // 关闭流,将导致数据写到浏览器上 out.close(); request.getRequestDispatcher("/message.html").forward(request, response); }
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if (true) { request.getRequestDispatcher("/form.html").forward(request, response); } // 下面这个会报java.lang.IllegalStateException: Cannot forward after response has been committed // 所以每个跳转后最好加上return语句 request.getRequestDispatcher("/message.html").forward(request, response); }
运行结果:
能输出aaaa或者跳转到form.html,但是代码会抛异常:
如果在调用forward方法之前向Servlet引擎的缓冲区中写入了内容,只要写入到缓冲区的内容还没有被真正的输出到客户端,forword方法就可以正常被执行,原来写入到输出缓冲区中的内容将被清空,但是,已经写入到HttpServletResponse对象中的响应头字段信息保持有效。
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); // aaaa将不会在message.html中出现 out.write("aaaa"); request.getRequestDispatcher("/message.html").forward(request, response); }
运行结果:
4.3 请求重定向和请求转发的区别
一个web资源收到客户端请求后,通知服务器去调用另一个web资源进行处理,称之为请求转发。
一个web资源收到客户端请求后,通知浏览器去访问另一个web资源,称之为请求重定向。
RequestDispatcher.forward方法只能将请求转发给同一个web应用中的组件;而HttpServletResponse.sendRedirect方法还可以定位到同一站点的其他web应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。
HttpServletResponse.sendRedirect方法重定向后,浏览器地址栏的URL会发生变化,由初始的URL变成重定向后的目标URL;RequestDispatcher.forward请求转发,浏览器地址栏URL不会变化。
HttpServletResponse.sendRedirect会有两次访问请求;RequestDispatcher.forward只有一次访问请求。
5. 利用referer实现防盗链
我们经常会遇到别人在微信群发了一个连接,点击进去后发现直接跳转到了网站首页,通过首页才能跳转到想看的网页。这个就利用了referer实现防盗链:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title></title> </head> <body> 首页 <a href="/HttpServletRequestDemo7">消息显示</a> </body> </html>
/** * 利用referer实现防盗链 */ @WebServlet(name = "HttpServletRequestDemo7") public class HttpServletRequestDemo7 extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String referer = request.getHeader("referer"); System.out.println(referer); if (referer == null || !referer.startsWith("http://localhost")) { response.sendRedirect("/index.jsp"); return; } request.getRequestDispatcher("/message.html").forward(request, response); } }
运行结果:
可以看到都是调用HttpServletRequestDemo7,直接输入(referer为null)是不能获取到message.html的,通过首页跳转才可以。