http host header

[size=small]在http 1.0版中,请求头中是不带host行的,到了http 1.1后,加入了host行

http request header 中的host行:

GET / HTTP/1.1
Host: www.google.com.cn

一台网络服务器上面可以放成千上万个网站(虚拟主机),当对这些网站的请求到来时,服务器能够根据Host这一行中的值来确定本次请求的是哪个具体的网站

http 1.1中不能缺失host行,如果缺失,服务器返回400 bad reques


通过telnet程序连接上tomcat服务器上的8080端口,此端口其实就tomcat用来监听http请求的端口[/size]
[img]http://dl2.iteye.com/upload/attachment/0089/4245/adcaa529-3851-3955-82a7-8d6ab90183e8.jpg[/img]

[size=small]同时按下Ctrl+] 回车,打开telnet回显功能
此时就可以看到我们输入的内容了

[color=darkred]测试向Tomcat服务器发送请求[/color]

[b]GET请求[/b]
[img]http://dl2.iteye.com/upload/attachment/0089/4256/872a2de5-8d41-3356-bec0-bcaf9ce96d6c.jpg[/img]

[b]POST请求[/b][/size]
[img]http://dl2.iteye.com/upload/attachment/0089/4264/0d41eb15-be93-3142-b763-ed7161305bb1.jpg[/img]

[b]缓存相关的头[/b]
禁止浏览器缓存
Pragma: no-cache HTTP1.0
Cache-Control: no-cache
Expires: 0

[size=small]服务器响应头:Last-Modified / Etag
客户端请求头:If-Modified-Since / If-None-Match
客户端(浏览器)第一次向服务器请求某个web组件,服务器返回的响应中会包含Etag,Last-Modified头,下次客户端再向服务器请求同一web组件,会将上一次服务器返回的Etag值作为If-None-Match头,将Last-Modified的值作为If-Modified-Since头作为请求头发给服务器,服务器会根据这些头信息判断请求的web组件是否为最新的,若没有更新,则简单返回304状态码,让客户端拿本地缓存。如果需要更新,则返回最新的web组件内容,同时包含新的Etag / Last-Modified头。这种机制可以避免服务器重复发送内容给客户端,但是还是会产生一个HTTP请求/响应。
Etag:W/"324-1379566963526"

ETag是响应头,If-None-Match是请求头。Last-Modified / If-Modified-Since的主要缺点就是它只能精确到秒的级别,一旦在一秒的时间里出现了多次修改,那么Last-Modified / If-Modified-Since是无法体现的。相比较,ETag / If-None-Match没有使用时间作为判断标准,而是使用一个特征串。Etag把Web组件的特征串告诉客户端,客户端在下次请求此Web组件的时候,会把上次服务端响应的特征串作为If-None-Match的值发送给服务端,服务端可以通过这个值来判断是否需要从重新发送,如果不需要,就简单的发送一个304状态码,客户端将从缓存里直接读取所需的Web组件。

服务器发出的响应,还可以通过Expires和Cache-Control头告诉客户端缓存web组件
Expires: Thu, 19 Sep 2013 05:02:43 GMT
如果服务器时间和客户端时间不一致,会导致这个头失效。
Cache-Control:max-age=5 单位是秒,时间是相对客户端的,不会出现Expires头的问题。
Expires头在HTTP1.0和HTTP1.1下都有效,而Cache-Control只在HTTP1.1下有效,大多数情况下同时发送这两个头会是更好的选择,客户端会优先使用Cache-Control头。

响应中同时包含Expires/Cache-Control头和Last-Modified/Etag头是一种比较好的处理方式,如果用户仅仅只是在浏览器地址栏上回车重新访问一次web组件,如果此时Expires/Cache-Control指定的过期时间还没到,则不会再向服务器端发送请求。如果用户通过F5重新请求某个web组件,此时Last-Modified/Etag就起作用了,若请求的web组件不需要更新,服务器端仅仅只返回304状态码。
[b]
Etag的弊端[/b]
对于只有一个Server的网站,Etag使用没什么问题,但是现在稍微上点规模的网站都需要Scale Out,也就是说需要前端一个Load Balancer,后面接多台Server来处理请求,俗称Cluster,既然是Cluster,那么每个请求到底返回什么结果应该和分配到哪个 Server无关,不过这个ETag可能就坏事了。假如用户的第一次请求分配给Server A,返回“ETag: "abcdefg1234:0001"”,但是第二次请求分配给了Server B,Server B上这个资源和Server A上的一模一样,但是计算出这个资源的ETag是"abcdefg1234:0002",这下麻烦了,虽然内容一样,但是ETag不匹配,还是浪费了带宽把资源发送了一遍,冤枉啊!而事实上,不同Server上的ETag很有可能不同,对于Apache,ETag的计算考虑了inode,对于 IIS,ETag考虑了metabase的修改版本,要保证不同server上的这些信息一致,有点小难。不过不是有Last-Modified/If- Not-Modified吗?Server端看到If-Modified-Since,对照一下时间对得上,不管If-None-Match,可以直接发回304(Not Modified)呀,很不幸,RFC2616对这种情况做了规定,如果既有If-None-Match又有If-Modified-Since,除非两者不冲突,不然不会返回304。[/size]
参考:[url]http://tech110.blog.51cto.com/438717/549764[/url]


/**
* Ctrl+F5 强制刷新 不管有没有缓存,都向服务器发送请求,且请求头中不包含If-Modified-Since等头字段
* 会包含Cache-Control:no-cache和Pragma:no-cache
*
* F5 会向服务器发送请求,同时会将If-Modified-Since请求头带上, Expires和Cache-Control无效
*
* 直接在浏览器地址栏回车,如果上一次响应中包含了Expires或Cache-Control头信息, 且时间还没有过期, 则不会再向服务器发出请求
*/
long time = request.getDateHeader("If-Modified-Since");
System.out.println(time);
if ((time + 60 * 1000) > new Date().getTime()) {
//如果距离上一次请求的时间不到60秒,返回304,让客户端直接拿缓存数据
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
return;
}

response.setContentType("text/html;charset=UTF-8");
response.setDateHeader("Last-Modified", new Date().getTime());
response.setDateHeader("Expires", new Date().getTime() + 60 * 1000); //毫秒
response.setHeader("Cache-Control", "max-age=60");//秒
response.getWriter().write("Hello, World!!!");
response.getWriter().write("<br/>");
response.getWriter().write("你好,世界!!!");


[b]Transfer-Encoding: chunked[/b]
[size=small]HTTP1.1下,如果服务器端返回的内容不能一次传递完,需要经过多次传送,则会在响应头中加入Transfer-Encoding头,告知客户端。如果数据是一次传完,响应头中会包含Content-Length头,告诉客户端接收内容的长度。
[/size]

GenerateImageServlet.java
//以流的方式将一张图片写到客户端,每次写1000字节
byte[] buf = new byte[1000];

int len = 0;
while (-1 != (len = in.read(buf))) {
response.getOutputStream().write(buf, 0, len);
response.getOutputStream().flush();
}

MainTest.java
//连上tomcat,发送一个HTTP请求,打印接收到的响应内容
Socket client = new Socket(InetAddress.getByName("localhost"), 8080);
InputStream in = client.getInputStream();
OutputStream out = client.getOutputStream();
//请求行
out.write("GET /tomcat_cache/GenerateImageServlet HTTP/1.1\r\n"
.getBytes());
//请求头
out.write("Host: localhost\r\n".getBytes());
//一个空行加实体内容,由于此处是GET请求,不包含实体内容。
out.write("\r\n\r\n".getBytes());
out.flush();

BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line = null;
while (null != (line = reader.readLine())) {
System.out.println(line);
}

out.close();
reader.close();
client.close();

####################运行结果#####################
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=E9A08F1E2B1F491DD13F66ABBA6ABA62; Path=/tomcat_cache
Transfer-Encoding: chunked
Date: Thu, 19 Sep 2013 07:28:55 GMT

3e8(十六进制,表示传递的数据长度为1000字节)
#$%ERT#$^@$@#$@^%$&%$(二进制串)
3e8
#$%ERT#$^@$@#$@^%$&%$(二进制串)
......
0(表示没有可传递的数据了)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值