l WEB服务器回送给WEB客户端的HTTP响应消息分为三个部分:
ü 状态行
ü 响应消息头
ü 消息正文(也叫实体内容)
今天我们就是来控制这三个部分的。
HTTP/1.1 200 OK -----状态行
Server: Apache-Coyote/1.1
Content-Type: text/html --------------------》消息响应头
Content-Length: 0
Date: Fri, 25 May 2012 03:46:22 GMT
(空一行)
实体内容在这里。
两种发送状态码的方式:
// response.setStatus(//这一种只设置状态码,比较单一,可以自己指定打印出来什么。
// 404
// );
// response.sendError(404);//这一种不给你设置了状态码,还自动转到相应的404页面,把你的要打印的东西的缓存清空,显示自己的404.
302状态码是指我不在这了,已经搬家了,并且已在响应消息头里面要设置一个location。告诉搬到哪了,然后浏览器会重新发出请求到location返回正确的页面,这两步过程在servlet中有一个方法sendRedirect
response.sendRedirect("/day06_servlet_01/xxx.html");
首先:
HTTP/1.1 302 Moved Temporarily
Server: Apache-Coyote/1.1
Location:http://localhost:8888/day06_servlet_01/xxx.html
Content-Length: 0
Date: Fri, 25 May 2012 04:06:19 GMT
然后:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=GBK
Content-Length: 315
Date: Fri, 25 May 2012 04:06:20 GMT
北京传智播客公司欢迎你
上面的更改状态码,讲的如何操纵消息头
下面讲如何操纵响应消息头。
设置响应消息头的方法:
setHeader
(String name,String value);
可以把响应头的名字设置为任意的,但是只有你设置为正确的浏览器才会识别,才会起作用,例如:
response.setHeader("Content-Length2","88");
response.setHeader("Content-Length","88");
out.println("test");
我们单独设置其中一个,当设置Content-Length2时就是一个响应头,能够显示出来,不起任何作用,如果设置为Content-Length那么它起作用,因为它告诉浏览器我要88个字节,但是只传递了4个字节,那么浏览器会一直等待,直到浏览器断开链接都会结束请求,显示”test”.其实所有的都可以通过setHeader来设置,但是SUN发现有的用的太频繁了,所以单独又弄一些个新的方法。如setContentLength,setDateHeader,setContextType
其实对响应消息头的每一个属性方法中都有单独定义:
// response.setContentLength(4);
response.setDateHeader("Date",new Date(2012,5, 5, 5, 5).getTime());
极为重要的总结:
早期在serlvet中,往客户端浏览器发数据要这样写:
response.setContentType("text/html;charset=”GBK");
response.getOutputStream().write("中国".getBytes("GBK"));
第一个行,告诉浏览器我传过来是字符是按照GBK编码的,请用GBK解码,第二行,是把将要传过去的数据进行GBK编码,两者必须一致方可,如果不一致,这就是乱码产生的原因,即,先告诉别人用什么解码,然后自己再按照这个告诉别人的码去编成相应的码传递过去。如果你不指定按什么样的编码传递过去,它默认是java系统平台编码(GBK),如果你告诉浏览器以会样的方式解码,不同的浏览器有不同的默认方式,所以两者要统一,都不可少。
后来发现这样用的太多了,太频繁了,简化一下,不需要自己去编码了随便发。
response.setContentType("text/html;charset=”GBK");
response.getWriter().println("中国");
因为第一句话,已经起了两个作用,第一、告诉客户端浏览器你要用什么样的东西解码,
第二、自己发过去的数据也按照,第一行所设置的编码方式进行编码。
第一行,先设置它是一种文本格式,然后再说明这种文本格式需要怎么样编码,
如果不写第二个,那么会按照ISO-8859-1编码方式,也可以用这个方法追加:
response.setCharacterEncoding("UTF-8");
如果用getWrite发送那么这一行就具有上述所说的两个作用,
第一、告诉客户端浏览器你要用什么样的东西解码,
第二、自己发过去的数据也按照,第一行所设置的编码方式进行编码。
一会说String.getBytes()默认按GBK(它是按照java平台默认编码方式),一会又说response.getWriter()输出的字符串默认按ISO8859-1编码(它是按照tomcat默认编码方式),
java虚拟机默认按操作系统相关的编码,tomcat默认按iso8859-1
禁止浏览器缓存当前文档内容:
l response.setDateHeader("Expires",0);
l response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache");
这三种要一起用,因为不同的浏览器不一定支持哪一个。
比喻:医生给病看病,知道三服药肯定有一副能治好,但是不敢肯定是哪一副,三幅都开。
在之前,我们有这样一个需求,就是说服务器发过去的数据,浏览器如何知道自己用什么样的东西解码,难倒让用户去选择 查看---》编码---》UTF-8\GBK等,这是不可能的,所以我们就写那个响应消息头,在那里面告诉浏览器你要用什么样的东西解码。
但是很显然,这样适用于动态网页,但是如果是html静态页面呢?怎么办呢?在html中有一个标签:<meta http-equiv="content-type" content="text/html; charset=UTF-8">那么浏览器在解析时间会自动按照UTF-8去解析,当然,服务器也是按照自己文件中所写的那样去编码发送的。显然,这个静态网页标签也是两个作用。
还有一个问题<meta http-equiv="content-type" content="text/html; charset=UTF-8">这行代码无论你放在哪里,放在最后它也会先被解析,这是非常重要的,你放在文本后面,它也会先被解析,所以meta标签在html先被解析。
<meta http-equiv="Refresh" content="3"/> 这个可以让静态网页刷新。
静态网页解决缓存:
ü <meta http-equiv="Expires"content="0">
ü <meta http-equiv="Cache-Control"content="no-cache">
ü <meta http-equiv="Pragma"content="no-cache">
ü // //下载附件问题中英文附件只能用getOutputStream();
ü // Stringfilename = request.getParameter("filename");
ü // //以流的形式获得这个文件getResourceAsStream这个可以获得任何位置的文件,与类加载不同。
ü // InputStreaminputStream =this.getServletContext().getResourceAsStream("/WEB-INF/"+filename);
ü // //这样仅仅是把文本读取了,如何下载呢,通过设置响应消息头。
ü // response.setContentType("application/octet-stream");
ü response.setHeader("Content-Disposition","attachment;filename="+filename);
ü //
ü // copyStream(inputStream,response.getOutputStream());
//上面是英文,如何下载带有中文文件名的呢?
我们在这里直接把中文的文件名给写死了,因为这样不会涉及到获取的问题,如果涉及到获取又是一个乱码问题,先研究一个方面。
InputStream inputStream = this.getServletContext().getResourceAsStream("/WEB-INF/"+"中文.txt");
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition","attachment;filename="+URLEncoder.encode("中文.txt","utf-8"));
copyStream(inputStream,response.getOutputStream());
filename="+URLEncoder.encode("中文.txt","utf-8");
这句话是为什么,第一,我们上面通过response设置的编码是指响应正文内的编码方式,那么响应消息头也有字符,它是按照什么样的编码呢?难倒也是我们随意指定的吗?完全不是,浏览器的消息响应头的编码统一采用UTF-8的方式编码,所以如果我们要传递的响应消息头中有中文,那么要转换成UTF-8. attachment;filename=%E4%B8%AD%E6%96%87.txt这个就是中文两个字对应的,一个汉字对应三个。(UTF-8汉字为什么占3个字节?)
Servlet不会接收到一个数据就发送给浏览器一个数据,只是等到缓冲区满了以后,再输送到浏览器。超过缓冲区会采用chuncked编码方式,分批传送。
l Servlet程序输出的HTTP消息的响应正文首先被写入到Servlet引擎提供的一个输出缓冲区中,直到输出缓冲区被填满或者Servlet程序已经写入了所有的响应内容,缓冲区中的内容才会被Servlet引擎发送到客户端。
l 使用输出缓冲区后,Servlet引擎就可以将响应状态行、各响应头和响应正文严格按照HTTP消息的位置顺序进行调整后再输出到客户端。
l 如果在提交响应到客户端时,输出缓冲区中已经装入了所有的响应内容,Servlet引擎将计算响应正文部分的大小并自动设置Content-Length头字段。
l 如果在提交响应到客户端时,输出缓冲区中装入的内容只是全部响应内容的一部分, Servlet引擎将使用HTTP 1.1的chunked编码方式(通过设置Transfer-Encoding头字段来指定)传输响应内容。
l Servlet执行完for语句后,缓冲区满,但容器不敢肯定Servlet是否还有内容输出,所以,容器将缓冲区的内容输出给浏览器时,无法确定整个实体内容的长度,只知道当前要输出的这块内容的大小,所以它用chuncked传输方式。
图像访问计数器:
大家首先要知道一个网站的页面能够引用另一个网站的图像!