(JavaEE-05)Response与Request

懵懂的女人 提交于 2019-11-28 12:47:28

如何才算掌握Servlet

  • ServletConfig
  • ServletContext
  • Request
  • Response
  • Cookie
  • Session

上面这些对象(当然不止这些,剩下的对象查阅ServletAPI,不是JavaEEAPI)都是web服务器在条用Servlet时所创建的交给Servlet的对象,将这些对象的API掌握熟练,就基本上掌握Servlet技术了,剩下的就是你的Java编程功力了,基本都是设计方面的事了。

Web服务器

web服务器接受到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象和代表相应的response对象。如果需要获取客户端的相关信息,就使用request对象,需要向客户端发送数据,就使用response对象

这里的request对象和response对象都不是标准的HTTP协议的请求和响应,而是Web服务器根据标准的HTTP协议的请求和响应,然后再根据Servlet规范(接口)实现的Web对象。

###Servlet技术 其实Servlet技术就是一套接口,这个接口是由当年的SUN公司指定的,Tomcat是一个web服务器,也是Servlet和JSP的容器,为什么它是Servlet与JSP的容器呢,原因就是它实现了SUN规定的那一套关于Servlet和JSP的规范与接口,所以在查阅ServletAPI时你会发现,很多都是接口,这是正常的,具体的显示类是由Tomcat来完成的,我们只管调用。HttpServletResponse与HttpServletRequest都是接口。如果你自己编写了一个服务器,而且实现了Servlet与JSP的接口与规范,那么你自己编写的这个服务器也可以是Servlet和JSP的容器(不完全的JAVAEE容器,因为完全的还需要实现EJB相关接口和规范)。

HttpServletResponse

Response对象代表响应,一个标准的HTTP响应包含三部分:状态行响应头响应数据。 常用方法有:

  • setStatus(int sc),设置响应的状态信息
  • setHeader(java.lang.String name, java.lang.String value),设置响应的头信息
  • getWriter(),返回一个PrintWriter对象,给客户端发送信息
  • getOutoutStream() ,返回一个ServletOutputStream对象,给客户端发送流信息

在学习过程中要注意,学习什么技术就查什么文档,例如现在在学习JavaEE中的Servlet技术,那么就查阅ServletAPI,不要查阅JavaEEAPI,这样更加方便,清晰。

###ResponseAPI

###response常见应用

  • 向客户端输出中文数据

    • OutputStream向客户端发送中文数据(默认编码与设定编码的问题,乱码的原因:客户端使用系统默认编码),处理方法:设置响应头信息
    • 使用HTML语言里面的<meta>标签来控制浏览器行为(模拟一个http响应头),也可以解决乱码问题
    • 使用OutputStream输出数字1,应该字符化
    • 使用PrintWriter来输出,设置response的编码(response默认的编码问题),还需要告诉浏览器(客户端)以什么编码方法打开,使用response的setHeader,简写可以使用setConteType
  • 文件下载和中文文件的下载

    • 获取需要下载的文件、通知浏览器以下载的方式打开、向浏览器写出数据
    • 如果下载文件的名字是中文,必须使用URL编码来进行处理
  • 输出随机图片

    • 在内存中创建一张图片
    • 得到图片
    • 设置背景颜色
    • 设置图片边框
    • 设置图片干扰线
    • 向图片上写数据
    • 把图片发送给客户端
    • 使用中文做验证
    • 设置浏览器不要缓存图片
  • 定时刷新网页

    • 使用response的消息头就可以让浏览器定时刷新网页
    • 使用meta标签模拟(<meta http-equiv='refresh' content='3;url=/webapp/index.html'>
  • 请求的重定向

    • 重定向与转发的区别(一个向服务器发了两次请求,一个向服务器发了一次请求)
    • 重定向发生,地址栏的地址会变化(重定向会增加服务器压力)
    • 使用 302 状态码和 location 头来完成,也可以使用response的重定向跳转方法来完成

###response的细节

  • getOutputStreamgetWriter方法分别用于得到输出二进制数据、输出文本数据的ServletOutputStream和PrintWriter对象
  • 这两个方法是互斥的,调用了其中的一个,另一个就不能再调用
  • 在一个请求的整个调用链中,只能有一个流存在,如果需要写多种数据,使用字节流来完成
  • Servlet引擎在service结束后,会自动检测response的流是否关闭,如果没有会自动关闭,然后再销毁Servlet,但是自己使用的流需要自己手动关闭

#HttpServletRequest HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,通过这个对象,就可以获取客户端的相关信息。

####常用方法:

  • getRequestURL方法返回客户端发出请求时的完整URL,资源在互联网上的位置
  • getRequestURI方法返回请求行中的资源名部分,资源的位置
  • getQueryString 方法返回请求行中的参数部分
  • getRemoteAddr方法返回发出请求的客户机的IP地址,屏蔽IP
  • getRemoteHost方法返回发出请求的客户机的完整主机名,注册DNS的主机名称,如果没有注册,返回IP
  • getRemotePort方法返回客户机所使用的网络端口号
  • getLocalAddr方法返回WEB服务器的IP地址
  • getLocalName方法返回WEB服务器的主机名
  • getMethod得到客户机请求方式

####获取客户端请求头:

  • getHead(name)方法
  • getHeaders(String name)方法
  • getHeaderNames方法

####获取客户端请求参数:

  • getParameter(name)方法
  • getParameterValues(String name)方法
  • getParameterNames方法
  • getParameterMap方法
  • getInputStream方法

###Request常见应用

####防盗链 防止自己网站的Web资源被别的网站使用。如果你有一个Servet,可以返回一些Web资源(图片、文章等等),那么在别的网站系统中,直接使用<a>链接,或者发送一个http请求给你的Servlet应用,那么就能获取你网站的Web资源。

  • 使用Request对象的getHeader(“referer”)方法来获取 referer 信息,rederer可以告诉我们当前这个请求是从哪个网站点击过来的。
  • 如果没有使用网页点击,而是直接发送的http请求,那么 rederer 的值为null
  • 检测 referer 的开头是否是本站,而且不能为 null,否则就重定向到本站首页

####获取各种表单输入项的数据 如果需要向服务器发送一系列数据,可以使用表单来完成。表单可以提交表单中的表单元素(表单项)的数据到服务器,浏览器会把表单中的可用元素(有name属性、disabled属性不为false的元素)的值封装起来。如果表单以get方式提交,那么这些值就会以 url 参数的形式发送给服务器,如果使用的是 post 方式提交,那么浏览器会将这些数据添加到 http 请求的消息体中(负载)发送给服务器。

常见表单元素:

  • text
  • password
  • radio,如果两个radio的name相同,就表明它们是一组,每次只会有一个被选中,默认选中使用checked = "checked"设置,使用 value 值来提交真正的数据
  • checkbox,多个值的获取,将多选按钮的名字都设置能一样的,在服务端使用 getParameterValues(name)方法来获取多个值,返回值是一个数组,使用value值来提交真正的数据
  • file
  • select,配合 option 项来提交值,select 元素来设置name,具体的值用 option来设置
  • textarea,默认值的设置不是用 value ,在标签体中来设置
  • hidden,隐藏域

对于表单提交的数据,在服务端一定要做验证才能使用,不然很容易发生异常

####请求数据的中文乱码问题 在做web开发时,经常会遇到乱码的问题,最好的解决乱码的方式就是从一开始就统一编码。

  • 如果出现乱码,首先要分析出现乱码的原因,也就是确定是哪一个环节导致了乱码
  • 一般常见的是:request的默认编码是 IOS8859-1,而页面提交的数据(页面的编码可以使用响应头和<meta>标签来设置,一般推荐UTF-8)不是这个编码。对于这种编码一般很好解决,使用 request的 setCharacterEncoding(encoding) 方法来设置 request的编码就可以了,但是这种设置仅对 post 方式提交的请求有效
  • 对于以 get 方式提交的请求,在Servlet中处理的话,只能使用手动的转码来实现,将 ISO8859-1 转成响应的编码。
  • get 方式提交的请求的乱码,还有一种方式可以解决乱码:改变 Tomcat 的配置(给连接器配置一个属性:URIEncoding="UTF-8")。
  • 如果超链接中提交的数据包含中文,一定要进行URL编码处理

关于get的乱码解决还有一种方式,就是使用 useBodyEncodingForURI="true",这种配置,这个配置的意思是:URI的编码用request实际设置的编码,这样配置后,request的 setCharacterEncoding(encoding) 对于get请求一样有效了。 对于改变服务器配置来解决乱码的方法,在实际开发中并不推荐,不要依赖服务器。

####request对象实现请求转发 使用request也可以实现请求的转发,在实际开发中,使用request做请求转发的多,一般不使用ServletContext做转发。如果在转发过程中需要传值到转发资源,使用request的setAttribute 方法来传值,在实际开发中,是使用 request 来进行转发和传值的,不使用ServletContext。因为ServletContext都整个Web应用中的Servlet共享,容易出现覆盖的问题,而request是独立的,不存在这个问题。 request也是一个域对象,是一个容器。

请求转发主要用来实现MVC设计模式。在MVC设计模式中,都是使用Servletl来处理用户请求,并且产生用户需要查看的数据,然后转发给jsp来显示,转发给jsp显示时,会把数据存在request域里面带给jsp。

####request域

  • setAttribute 方法
  • getAttribute 方法
  • removeAttribute 方法
  • getAttributeNames 方法

####请求转发中的细节 在使用转发的时候,有些小细节要注意:

  • 如果在调用forward方法之前,在Servlet程序中写入的部分内容已经被真正传送到了客户端,forward方法将抛出参数异常。(比如使用PrintWriter发送数据给客户端,然后关闭流,然后再使用request来转发,就会抛异常)
  • 多次请求转发也是不可取的,一样会抛参数异常
  • 关闭response的流,意味着提交响应结果到客户端,如果不关闭,就没有提交,还是有机会做别的响应处理的,那么别的响应处理将会覆盖掉之前的响应(之前的响应被清空,但是对于响应头的设置信息,会保留下来

总结:在请求转发的前后,都不要写数据,写了也没有用!!!在Servlet中,只产生数据,但是不做输出,输出交给JSP(MVC)

####请求重定向和请求转发的区别

  • 一个web资源收到客户端请求后,通知服务器去调用另外一个web资源进行处理,称之为请求转发
  • 一个web资源收到客户端请求后,通知浏览器去访问另外一个web资源,称之为请求重定向
  • RequestDispatcher.forward方法只能将请求转发给同一个WEB应用中的组件;而HttpServletResponse.sendRedirect 方法还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源
  • 如果传递给HttpServletResponse.sendRedirect 方法的相对URL以“/”开头,它是相对于整个WEB站点的根目录;如果创建RequestDispatcher对象时指定的相对URL以“/”开头,它是相对于当前WEB应用程序的根目录
  • 调用HttpServletResponse.sendRedirect方法重定向的访问过程结束后,浏览器地址栏中显示的URL会发生改变,由初始的URL地址变成重定向的目标URL;调用RequestDispatcher.forward 方法的请求转发过程结束后,浏览器地址栏保持初始的URL地址不变
  • HttpServletResponse.sendRedirect方法对浏览器的请求直接作出响应,响应的结果就是告诉浏览器去重新发出对另外一个URL的访问请求;RequestDispatcher.forward方法在服务器端内部将请求转发给另外一个资源,浏览器只知道发出了请求并得到了响应结果,并不知道在服务器程序内部发生了转发行为
  • RequestDispatcher.forward方法的调用者与被调用者之间共享相同的request对象和response对象,它们属于同一个访问请求和响应过程;而HttpServletResponse.sendRedirect方法调用者与被调用者使用各自的request对象和response对象,它们属于两个独立的访问请求和响应过程

####RequestDispatcher的include方法

  • RequestDispatcher.include方法用于将RequestDispatcher对象封装的资源内容作为当前响应内容的一部分包含进来,从而实现可编程的服务器端包含功能
  • 被包含的Servlet程序不能改变响应消息的状态码和响应头,如果它里面存在这样的语句,这些语句的执行结果将被忽略

####Web工程中地址的写法 在web开发中,经常会使用地址,如:

  • this.getServletContext().getRealPath("/")
  • request.getRequestDispatcher("/")
  • response.sendRedirect("/")
  • response.getWriter().write("<meta http-equiv='refresh' content='3;url=/'>")
  • <form aciont="/">
  • <a href="/">,<img src="">

对于这些地址,里面都可以用"/",这些有什么区别呢?总结:凡是给服务器用的地址,"/"代表当前web应用;凡是给浏览器用的地址,"/"代表网站(webapps) 还有"/"与"",前者使用在虚拟路径或者URL地址;后者使用在硬盘地址。 使用斜杠的地址,都是绝对地址,还有一些情况是需要相对地址的(后续课程)。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!