接下来记录一下Servlet Response相关的信息,在service方法中使用的是HttpServletResponse,它继承自ServletResponse,扩展了Http协议相关的内容,下面简单记录一下它的基本用法。
response组成内容
以下是一个常见response响应的内容,它包括状态行、响应头、一个空行和实体内容,其中"HTTP/1.1 200 OK"就是状态行,包括协议、状态代号和状态描述信息,下面有若干响应头,空行和实体内容这里没展示。
response常用方法
response提供了常用的api,有如下三类,通过它可以实现response的诸多功能。
设置状态码
设置状态码有如下API
(1)response.setStatus(int status) 设置状态码
(2)response.setStatus(int status,String description),java8中已经被弃用了,被标记为过时deprecated
下面设置状态码为404,测试。
1 package com.boe.response; 2 3 import javax.servlet.ServletException; 4 import javax.servlet.annotation.WebServlet; 5 import javax.servlet.http.HttpServlet; 6 import javax.servlet.http.HttpServletRequest; 7 import javax.servlet.http.HttpServletResponse; 8 import java.io.IOException; 9 10 /** 11 * 设置状态码 12 */ 13 @WebServlet("/ResponseDemo05") 14 public class ResponseDemo05 extends HttpServlet { 15 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 16 //设置404 17 response.setStatus(404); 18 response.getWriter().write("Hello status"); 19 } 20 21 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 22 doPost(request, response); 23 } 24 }
访问页面后发现尽管能正常访问到资源,但是状态码被设置成了404。
状态码404
设置响应头
设置影响头的方法,可以影响到页面的效果,有时候需要和上面设置状态码的方法配合使用,它常用的方法如下,前三个是set,后三个是add。
1 package com.boe.response; 2 3 import javax.servlet.ServletException; 4 import javax.servlet.annotation.WebServlet; 5 import javax.servlet.http.HttpServlet; 6 import javax.servlet.http.HttpServletRequest; 7 import javax.servlet.http.HttpServletResponse; 8 import java.io.IOException; 9 10 /** 11 * 设置使用setIntHeader方法 12 */ 13 @WebServlet("/ResponseDemo06") 14 public class ResponseDemo06 extends HttpServlet { 15 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 16 //设置刷新 17 /* response.setIntHeader("Refresh",2); 18 response.getWriter().write("<font color='blue' size='10px'>this is setIntHeader method"+"+"+Math.random()*100+"</font>");*/ 19 //设置发送数据长度,一个英文字符代表1个长度 20 response.setIntHeader("Content-Length",10); 21 response.getWriter().write("I come from china"); 22 23 } 24 25 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 26 doPost(request, response); 27 } 28 }
实际效果,会每隔2秒刷新一次页面,这里没有截取gif,使用两张贴图记录一下。
另外setIntHeader里如果设置Content-length,还可以控制输出到页面的数据长度,发现输出到页面的实际长度被截取了。
设置响应消息
有两种方法可以设置响应消息,如下。
response常用功能
response常用功能有请求重定向、控制缓存、页面刷新等。
请求重定向
请求重定向的原理就是设置状态码为302,并且在响应头里设置location的路径,就可以实现重定向,也可以直接使用现成api来实现。
1 package com.boe.response; 2 3 import javax.servlet.ServletException; 4 import javax.servlet.annotation.WebServlet; 5 import javax.servlet.http.HttpServlet; 6 import javax.servlet.http.HttpServletRequest; 7 import javax.servlet.http.HttpServletResponse; 8 import java.io.IOException; 9 10 /** 11 * 请求重定向 12 */ 13 @WebServlet("/ResponseDemo02") 14 public class ResponseDemo02 extends HttpServlet { 15 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 16 //原理实现 17 //设置状态码 18 response.setStatus(302); 19 //设置消息头 20 response.setHeader("Location","http://www.baidu.com"); 21 22 //api实现 23 //以上代码等效如下代码 24 //response.sendRedirect("http://www.baidu.com"); 25 } 26 27 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 28 doPost(request, response); 29 } 30 }
访问ResponseDemo02后页面跳转到百度,重定向的地址是会改变的。
控制缓存
控制缓存有三个api可以使用,可以通过设置影响头的Cache-Control、Pragma和Expires来控制,参考前面对响应头的介绍和如下代码。
1 package com.boe.response; 2 3 import javax.servlet.ServletException; 4 import javax.servlet.annotation.WebServlet; 5 import javax.servlet.http.HttpServlet; 6 import javax.servlet.http.HttpServletRequest; 7 import javax.servlet.http.HttpServletResponse; 8 import java.io.IOException; 9 import java.util.Date; 10 11 /** 12 * 浏览器缓存的设置 13 */ 14 @WebServlet("/ResponseDemo04") 15 public class ResponseDemo04 extends HttpServlet { 16 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 17 //设置不使用缓存 18 /*public void setDateHeader(String name, long date) 19 用给定名称和日期值设置响应头。该日期根据距历元时间的毫秒数指定。如果已经设置了头,则新值将重写以前的值。 20 containsHeader 方法可用于测试在设置其值之前头是否存在。*/ 21 //方式1 22 if(response.containsHeader("Expires")){ 23 response.setDateHeader("Expires",-1); 24 } 25 //方式2 26 response.setHeader("Cache-Control","no-cache"); 27 //方式3 28 response.setHeader("Pragma","no-cache"); 29 30 Date date=new Date(); 31 String time = date.toLocaleString(); 32 //设置使用缓存 33 //response.setDateHeader("Expires",System.currentTimeMillis()+1000*60*60*1);//1 hour 34 //response.setHeader("Cache-Control","max-age=60");//60 s 35 36 response.getWriter().write("<font color='blue'>"+time+"</font>"); 37 38 39 } 40 41 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 42 doPost(request, response); 43 } 44 }
当不使用缓存时,每次刷新一下页面,就会打印新的时间,这里就不展示了。当设置完使用缓存,在缓存的寿命范围内,时间都不会变的,目前在IE和火狐浏览器测试可以,chrome没有效果。
页面刷新
页面刷新可以设置响应头的Refresh,里面一个时间参数单位为秒,一个刷新后页面的url地址,注意使用url,这个可以用在注册后隔几秒跳转到主页这种场景。以下代码就是实现访问ResponseDemo03请求后,等待3秒会刷新进入百度主页的功能。
1 package com.boe.response; 2 3 import javax.servlet.ServletException; 4 import javax.servlet.annotation.WebServlet; 5 import javax.servlet.http.HttpServlet; 6 import javax.servlet.http.HttpServletRequest; 7 import javax.servlet.http.HttpServletResponse; 8 import java.io.IOException; 9 10 /** 11 * 定时刷新 12 */ 13 @WebServlet("/ResponseDemo03") 14 public class ResponseDemo03 extends HttpServlet { 15 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 16 //3 秒 17 response.setHeader("Refresh","3;url=http://www.baidu.com"); 18 } 19 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 20 doPost(request, response); 21 } 22 }
response乱码处理
涉及到响应,势必可能会有服务器和浏览器编解码不一致的问题,并会产生乱码,接下来使用字节流和字符流发送数据,查看乱码情况,使用如下基准代码进行调试,根据测试条件做调整即可。
1 package com.boe.response; 2 3 import javax.servlet.ServletException; 4 import javax.servlet.annotation.WebServlet; 5 import javax.servlet.http.HttpServlet; 6 import javax.servlet.http.HttpServletRequest; 7 import javax.servlet.http.HttpServletResponse; 8 import java.io.IOException; 9 10 /** 11 * 响应字节流和字符流的乱码处理 12 */ 13 @WebServlet("/ResponseDemo01") 14 public class ResponseDemo01 extends HttpServlet { 15 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 16 //1 字节流 17 System.out.println(response.getCharacterEncoding()); 18 //ISO-8859-1 tomcat默认的字符编码,针对字符流,对字节流无影响 19 //response.getOutputStream().write("china".getBytes()); 20 //getByte()默认使用平台的字符编码,即GBK,而浏览器默认使用GBK解码,因此没有乱码 21 //response.getOutputStream().write("中国".getBytes()); 22 /** 23 * 一般浏览器都会设置utf-8解码,这里需指定服务器编码方式为utf-8,设置浏览器解码也是utf-8 24 */ 25 //通知浏览器使用utf-8来解码 26 /*response.setHeader("Content-Type","text/html;charset=utf-8"); 27 response.getOutputStream().write("中国".getBytes("utf-8"));*/ 28 29 //2 字符流 30 //默认使用iso-8859-1将字符流转变成字节流,底层由Tomcat服务器来完成,会使用Tomcat默认的字符集 31 //通知服务端发送数据时字符集utf-8 32 //response.setCharacterEncoding("utf-8"); 33 //如果告诉浏览器使用何种字符集,则这句可以不用写,服务会在发送数据自动采用浏览器设置的字符集 34 //通知浏览器指定utf-8读取 35 //response.setHeader("Content-Type","text/html;charset=utf-8"); 36 37 //也可以用如下api 38 //response.setContentType("text/html;charset=utf-8"); 39 //response.getWriter().write("我是英文"); 40 } 41 42 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 43 doPost(request, response); 44 } 45 }
字节流发送数据
使用字节流发送数据使用ServletOutputStream的write方法,使用发现在不设置任何编码格式的情况下,浏览器能正常显示中文,并没有乱码产生,通过查看响应头发现也没有指定Content-Type。
这是因为用getByte方法得到字节数组时,使用的是平台默认的字符集,即GBK,而当不指定浏览器解码字符集时也是使用平台默认的字符集GBK,两者一致因此没有产生乱码。
一般浏览器会使用utf-8来解码,因此需要使用如下代码指定浏览器的解码字符集,以及服务器的编码字符集均为utf-8。
1 response.setHeader("Content-Type","text/html;charset=utf-8"); 2 response.getOutputStream().write("中国".getBytes("utf-8"))
修改后发现响应头里有指定Content-Type。
字符流发送数据
使用字符流发送数据使用PrintWriter的write方法,在不设置字符集的情况下,发现'我是英文'四个字显示四个问号,产生了乱码问题。
这是因为字符流本质上还是会转化为字节流,当服务器不指定字符编码时,会默认使用tomcat的字符编码,即iso-8859-1,而浏览器不指定解码时默认使用GBK,因此会产生乱码,另外iso-8859-1是单字节编码无法表示中文,'我是英文'最后返回给浏览器3f 3f 3f 3f,显示四个问号。
想要解决乱码问题也是通过统一编码方式,服务端使用setCharacterEncoding的方法指定,浏览器字符集有两种方法指定,两种都可以,本质上就是设置响应头里的Content-Type。
1 //默认使用iso-8859-1将字符流转变成字节流,底层由Tomcat服务器来完成,会使用Tomcat默认的字符集 2 //通知服务端发送数据时字符集utf-8 3 //response.setCharacterEncoding("utf-8"); 4 //如果告诉浏览器使用何种字符集,则这句可以不用写,服务会在发送数据自动采用浏览器设置的字符集 5 //通知浏览器指定utf-8读取 6 //response.setHeader("Content-Type","text/html;charset=utf-8"); 7 8 //也可以用如下api 9 //response.setContentType("text/html;charset=utf-8");
修改后浏览器能正常显示中文。