HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中。要得到浏览器信息,就找HttpServletRequest对象。
HttpServletRequest常用方法
获取客户端【浏览器】信息
- getRequestURL方法返回客户端发出请求时的完整URL。
- getRequestURI方法返回请求行中的资源名部分。
- getQueryString 方法返回请求行中的参数部分。
- getPathInfo方法返回请求URL中的额外路径信息。额外路径信息是请求URL中的位于Servlet的路径之后和查询参数之前的内容,它以“/”开头。
- getRemoteAddr方法返回发出请求的客户机的IP地址
- getRemoteHost方法返回发出请求的客户机的完整主机名
- getRemotePort方法返回客户机所使用的网络端口号
- getLocalAddr方法返回WEB服务器的IP地址。
- getLocalName方法返回WEB服务器的主机名
获取客户端请求头
- getHeader方法
- getHeaders方法
- getHeaderNames方法
获取客户端请求参数(客户端提交的数据)
- getParameter方法
- getParameterValues(String name)方法
- getParameterNames方法
- getParameterMap方法
HttpServletRequest应用
防盗链
防止简单的复制URL和粘贴URL就可以访问。
获取Referer这个消息头,判断Referer是否是从首页过来的。
//获取Referer消息头 String referer=request.getHeader("Referer"); //如果不是从首页或者地址栏直接访问 if(referer==null||!referer.contains("localhost:8080/index.jsp")){ response.sendRedirect(/index.jsp); return; } response.setContentType("text/html;charset=UTF-8"); response.getWriter().write("是跳转过来");
表单提交数据【通过post方式提交数据】
//设置request字符编码格式 request.setCharacterEncoding("UTF-8"); //获取单个值 String account=request.getParameter("userAccount"); String password=request.getParameter("password"); //获取多个值 String[] hobbies=request.getParameterValues("hobbies"); System.out.println(account); System.out.println(password); response.getWriter().write("OK");
超链接方式提交数据【通过get方式提交数据】
string url="servlet的地址?参数名="+参数值 &"参数名="+参数值;
response.sendRedirect(url);
//设置request字符编码格式 request.setCharacterEncoding("UTF-8"); String account=request.getParameter("userAccount"); String password=request.getParameter("password"); response.getWriter().write("OK");
实现转发
使用request的getRequestDispacher.forward(request,response)实现转发,做到的功能也是页面跳转。
//获取到requestDispatcher对象,跳转到index.html final RequestDispatcher requestDispatcher = request.getRequestDispatcher("/index.html"); //调用requestDispatcher对象的forward()实现转发,传入request和response的方法 requestDispatcher.forward(request,response);
之前讲过Servlet之间可以通过Servletcontext实现通讯,ServletContext也能称之为域对象,而request也可以称之为域对象,只不过ServletContext的域是整个web应用,而request的域仅仅代表一次http请求。
一个Servlet中代码
//设置参数 request.setAttribute("username","tony"); //获取RequestDispatcher对象 RequestDispatcher requestDispatcher=request.getRequestDispatcher("/Servlet2"); //调用requestDispatcher对象的forward()实现转发,传入request和response requestDispatcher.forward(request,response);
在Servlet2中代码
//获取到存进request对象的值 String userName=(String)request.getAttribute("username"); response.getWriter().write(userName);
可以使用ServletContext和request实现Servlet之间的通讯,一般原则:可以使用request就尽可能使用request。因为ServletContext代表着整个web应用,使用ServletContext会消耗大量的资源,而request对象会随着请求的结束而结束,资源会被回收。使用request域进行Servlet之间的通讯在开发中是非常频繁的。
转发的时序图
请求转发的细节
在调用forward方法之前,在Servlet程序中写入的部分内容已经被真正地传送到了客户端,forward方法将抛出异常。不要在转发之前写数据给浏览器。如果在调用forward方法之前向Servlet引擎的缓冲区中写入了内容,只要写入到缓冲区中的内容还没有被真正输出到客户端,forward方法就可以被正常执行,原来写入到输出缓冲区中的内容将被清空,但是,已写入到HttpServletResponse对象中的响应头字段信息保持有效。
ServletOutputStream servletOutputStream=response.getOutputStream(); servletOutputStream.write("---------".getBytes()); //关闭流,确保让数据到浏览器中 servletOutputStream.close(); //跳转,后台出现异常,无法跳转 final RequestDispatcher requestDispatcher = request.getRequestDispatcher("/index.html"); requestDispatcher.forward(request,response);
转发和重定向的区别
实际发生位置不同,地址栏不同
- 转发是发生在服务器的:转发是由服务器进行跳转的,在转发的过程中,浏览器的地址栏是没有发生变化的。浏览器是不知道该跳转的动作,转发是对浏览器透明的。实现转发只是一次的http请求,一次转发中request和response对象都是同一个。解释了使用request作为域对象能进行ServletServlet之间的通讯。
- 重定向式发生在浏览器的:重定向式由浏览器进行跳转的,进行重定向跳转的时候,浏览器地址会发生变化的。实现重定向的原理是由response的状态码和Location头组合而实现的。这是由浏览器进行的页面跳转实现重定向会发出两个http请求,request域对象是无效的,因为它不是同一个request对象。
用法不同
资源地址不同,给服务器用的直接从资源名开始写,给浏览器用的要把应用名写上
- request.getRequestDispatcher("/资源名 URI").forward(request,response); 转发时"/"代表的是本应用程序的根目录
- response.sendRedirect("/web应用/资源名 URI"); 重定向时"/"代表的是webapps目录
能够去往的URL的范围不一样
- 转发是服务器跳转只能去往当前web应用的资源
- 重定向是浏览器跳转,可以去往任何的资源
传递数据的类型不同
- 转发的request对象可以传递各种类型的对象,包括对象
- 重定向只能传递字符串
跳转的时间不同
- 转发时:执行到跳转语句时就会立刻跳转
- 重定向:整个页面执行完之后才执行跳转
转发是带着转发前的请求的参数的,重定向是新的请求。
- 转发:访问Servlet处理业务逻辑,然后forward到jsp显示处理结果,浏览器里URL不变
- 重定向:提交表单,处理成功后redirect到另一个jsp,防止表达重复提交,浏览器里URL变了。
RequestDispatcher的include()方法
写网页的时候,一般网页的头部和尾部都是不需要改变的,如果多个地方使用Servlet输出网头和网尾的话,需要把代码重新写一遍。而使用RequestDispatcher的include()方法就可以实现包含网头和网尾的效果了。
request.getRequestDispatcher("/Head").include(request, response); response.getWriter().write("-----------------------------------------"); request.getRequestDispatcher("/Foot").include(request, response);