HTTP
简介
超文本传送协议 (HTTP-Hypertext transfer protocol) 是一种详细规定了浏览器和万维网服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。
一.HTTP响应状态码
#1xx :指示信息--表示请求已接收,继续处理
100 :Continue,继续。客户端应继续其请求
101 :Switching Protocols,切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议.
#2xx :成功--表示请求已被成功接收、理解、接受
200 :OK,客户端请求成功
201 :Created,已创建。成功请求并创建了新的资源
202 :Accepted,已接受。已经接受请求,但未处理完成
203 :Non-Authoritative Information,非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本
204 :No Content 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档
205 :Reset Content,重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域
206 :Partial Content,断点下载时用到,客户端请求了一部分内容,服务器成功把这部分内容返回给它,这时候就是用这个状态。
#3xx :重定向--要完成请求必须进行更进一步的操作
300 :Multiple Choices,多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择
301 :Moved Permanently,永久跳转,原地址不存在了,url被指向到另一个地址。这个主要是搜索引擎相关,影响爬虫的检索行为。
302 :Found,临时跳转,服务器会返回一个新的url给客户端,客户端可以继续访问这个url来获取内容。
303 :See Other 查看其它地址。与301类似。使用GET和POST请求查看
304 :Not Modified,资源没有改变,客户端可以使用本地缓存的内容,常见于静态内容访问。
305 :Use Proxy,使用代理。所请求的资源必须通过代理访问
306 :Unused,已经被废弃的HTTP状态码
307 :Temporary Redirect,临时重定向。与302类似。使用GET请求重定向
#4xx :客户端错误--请求有语法错误或请求无法实现
400 :Bad Request,客户端请求有语法错误,不能被服务器所理解
401 :Unauthorized ,请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
402 :Payment Required,保留,将来使用
403 :Forbidden,服务器收到请求,但是拒绝提供服务
404 :Not Found,请求资源不存在,eg:输入了错误的URL
405 :Method Not Allowed,客户端请求中的方法被禁止
406 :Not Acceptable,服务器无法根据客户端请求的内容特性完成请求
407 :Proxy Authentication Required,请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权
408 :Request Time-out,服务器等待客户端发送的请求时间过长,超时
409 :Conflict,服务器完成客户端的PUT请求时可能返回此代码,服务器处理请求时发生了冲突
410 :Gone,客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置
411 :Length Required,服务器无法处理客户端发送的不带Content-Length的请求信息
412 :Precondition Failed,客户端请求信息的先决条件错误
413 :Request Entity Too Large,请求实体太大。常见的情况是上传大文件,但超出了服务器(比如nginx)限制。或者请求头或请求体超出了后端的server(比如tomcat)的设置(比如当前域名下cookie太多,超出了请求头限制)
414 :Request-URI Too Large,请求的URI过长(URI通常为网址),服务器无法处理
415 :Unsupported Media Type,服务器无法处理请求附带的媒体格式
416 :Requested range not satisfiable,跟断点续传有关,客户端请求的范围超出了服务器上文件大小。
417 :Expectation Failed,服务器无法满足Expect的请求头信息
#5xx :服务器端错误--服务器未能实现合法的请求
500 :Internal Server Error,服务器内部错误,不能返回正常的结果。比如最常见的应用抛出空指针异常未进行处理。
501 :Not Implemented,服务器不支持请求的功能,无法完成请求
502 :Bad Gateway,网关错误。常见的情况是反向代理后端的服务器(比如resin或tomcat)没有启动。
503 :Service Unavailable,服务不可用。比如服务器负载太高或者服务器已经停止服务。
504 :Gateway Time-out,网关超时。比如请求时长超出了服务器的响应时间限制。
二.请求报头
请求报头允许客户端向服务器端传递请求的附加信息以及客户端自身的信息。
常用的请求报头:
1.Accept
Accept请求报头域用于指定客户端接受哪些类型的信息。eg:Accept:image/gif,表明客户端希望接受GIF图象格式的资源;Accept:text/html,表明客户端希望接受html文本。
2.Accept-Charset
Accept-Charset请求报头域用于指定客户端接受的字符集。eg:Accept-Charset:iso-8859-1,gb2312.如果在请求消息中没有设置这个域,缺省是任何字符集都可以接受。
3.Accept-Encoding
Accept-Encoding请求报头域类似于Accept,但是它是用于指定可接受的内容编码。eg:Accept-Encoding:gzip.deflate.如果请求消息中没有设置这个域服务器假定客户端对各种内容编码都可以接受。
4.Accept-Language
Accept-Language请求报头域类似于Accept,但是它是用于指定一种自然语言。eg:Accept-Language:zh-cn.如果请求消息中没有设置这个报头域,服务器假定客户端对各种语言都可以接受。
5.Authorization
Authorization请求报头域主要用于证明客户端有权查看某个资源。当浏览器访问一个页面时,如果收到服务器的响应代码为401(未授权),可以发送一个包含Authorization请求报头域的请求,要求服务器对其进行验证。
6.Host(发送请求时,该报头域是必需的)
Host请求报头域主要用于指定被请求资源的Internet主机和端口号,它通常从HTTP URL中提取出来的,eg:
我们在浏览器中输入: http://www.guet.edu.cn/index.html
浏览器发送的请求消息中,就会包含Host请求报头域,如下:
Host:www.guet.edu.cn
此处使用缺省端口号80,若指定了端口号,则变成:Host:www.guet.edu.cn:指定端口号
7.User-Agent
我们上网登陆论坛的时候,往往会看到一些欢迎信息,其中列出了你的操作系统的名称和版本,你所使用的浏览器的名称和版本,这往往让很多人感到很神奇,实际上,服务器应用程序就是从User-Agent这个请求报头域中获取到这些信息。User-Agent请求报头域允许客户端将它的操作系统、浏览器和其它属性告诉服务器。不过,这个报头域不是必需的,如果我们自己编写一个浏览器,不使用User-Agent请求报头域,那么服务器端就无法得知我们的信息了。
请求报头举例:
GET /form.html HTTP/1.1 (CRLF)
Accept:image/gif,image/x-xbitmap,image/jpeg,application/x-shockwave-flash,application/vnd.ms-excel,application/vnd.ms-powerpoint,application/msword,*/* (CRLF)
Accept-Language:zh-cn (CRLF)
Accept-Encoding:gzip,deflate (CRLF)
If-Modified-Since:Wed,05 Jan 2007 11:21:25 GMT (CRLF)
If-None-Match:W/"80b1a4c018f3c41:8317" (CRLF)
User-Agent:Mozilla/4.0(compatible;MSIE6.0;Windows NT 5.0) (CRLF)
Host:www.guet.edu.cn (CRLF)
Connection:Keep-Alive (CRLF)
(CRLF)
三.响应报头
响应报头允许服务器传递不能放在状态行中的附加响应信息,以及关于服务器的信息和对Request-URI所标识的资源进行下一步访问的信息。
常用的响应报头
1.Location
Location响应报头域用于重定向接受者到一个新的位置。Location响应报头域常用在更换域名的时候。
2.Server
Server响应报头域包含了服务器用来处理请求的软件信息。与User-Agent请求报头域是相对应的。下面是
Server响应报头域的一个例子:
Server:Apache-Coyote/1.1
3.WWW-Authenticate
WWW-Authenticate响应报头域必须被包含在401(未授权的)响应消息中,客户端收到401响应消息时候,并发送Authorization报头域请求服务器对其进行验证时,服务端响应报头就包含该报头域。
例如:WWW-Authenticate:Basic realm="Basic Auth Test!" //可以看出服务器对请求资源采用的是基本验证机制。
四.实体报头
请求和响应消息都可以传送一个实体。一个实体由实体报头域和实体正文组成,但并不是说实体报头域和实体正文要在一起发送,可以只发送实体报头域。实体报头定义了关于实体正文(eg:有无实体正文)和请求所标识的资源的元信息。
常用的实体报头
1.Content-Encoding
Content-Encoding实体报头域被用作媒体类型的修饰符,它的值指示了已经被应用到实体正文的附加内容的编码,因而要获得Content-Type报头域中所引用的媒体类型,必须采用相应的解码机制。Content-Encoding这样用于记录文档的压缩方法,eg:Content-Encoding:gzip
2.Content-Language
Content-Language实体报头域描述了资源所用的自然语言。没有设置该域则认为实体内容将提供给所有的语言阅读
者。eg:Content-Language:da
3.Content-Length
Content-Length实体报头域用于指明实体正文的长度,以字节方式存储的十进制数字来表示。
4.Content-Type
Content-Type实体报头域用语指明发送给接收者的实体正文的媒体类型。eg:
Content-Type:text/html;charset=ISO-8859-1
Content-Type:text/html;charset=GB2312
5.Last-Modified
Last-Modified实体报头域用于指示资源的最后修改日期和时间。
6.Expires
Expires实体报头域给出响应过期的日期和时间。为了让代理服务器或浏览器在一段时间以后更新缓存中(再次访问曾访问过的页面时,直接从缓存中加载,缩短响应时间和降低服务器负载)的页面,我们可以使用Expires实体报头域指定页面过期的时间。eg:Expires:Thu,15 Sep 2006 16:23:12 GMT
HTTP1.1的客户端和缓存必须将其他非法的日期格式(包括0)看作已经过期。eg:为了让浏览器不要缓存页面,我们也可以利用Expires实体报头域,设置为0,jsp中程序如下:response.setDateHeader("Expires","0");
五.缓存控制
在互联网站的应用中,缓存几乎无处不在,在基于http的服务中,我们也可以对一些不常改变的内容在客户端进行缓存,这样在多次访问中可以复用缓存内容,加快访问速度,提升用户体验。
HTTP的协议里规定了一些用于缓存控制的http消息头:
1.Cache-Control(HTTP/1.1)/Pragma(HTTP/1.0):
指示客户端是否进行缓存以及缓存的时间是多长。默认值是private,也就是把内容缓存在用户私有空间。比如:Cache-Control:max-age=86400,must-revalidate,这是告诉客户端所请求的资源缓存一天(max-age单位是秒,相对时间),过期之后必须进行重新检验。
指定客户端(如果不强制刷新的话)在多长时间里可以不向服务器发请求,直接读本地缓存。
注意:
优先级:Cache-Control > Expires;
详细参数说明: http://condor.depaul.edu/dmumaugh/readings/handouts/SE435/HTTP/node24.html
不同浏览器的不同行为(刷新,后退,地址栏回车等)在实现上可能有差异;
- Last-Modified/If-Modified-Since:
Last-Modified是服务器端返回给客户端的资源最后修改时间戳,这样,客户端在下次请求时(比如强制刷新)会带上If-Modified-Since参数来校验资源是否有更新,没有更新的话服务器就返回304状态码,客户端直接取本地缓存的资源。这个时候只有请求开销,没有网络传输开销。注意:时间戳必须是格林威治(GMT)时间,比如:Last-Modified:Sat, 19 Oct 2013 09:20:15 GMT
2.ETag/If-None-Match:
ETag是根据文件属性通过一定算法生成的资源标识,也是用来确定客户端请求的资源是否有更新。如果服务器返回了一个ETag值给客户端,那么下次客户端请求时会带上If-None-Match参数来校验资源是否更新,没有更新的就返回304状态码。(效果基本等同于Last-Modified)
注意:
ETag需要计算,对于计算资源紧张的服务器来说是一种消耗,所以有些网站直接不使用ETag;
如果服务器在负载均衡后面,同一个资源的请求可能分发到不同的后端机器上,由于ETag的计算依赖于文件属性,不同机器上内容相同的文件可能生成的ETag不同,这样就可能使本来内容没变的文件通过ETag校验失败。这里有两种解决方案:一是etag计算不依赖于本地机器,比如直接算文件内容的md5值;二是在负载均衡器上把相同的url请求分发到同一台后端机器。
在我们的实际业务场景下,http的缓存具有非常大的用途,下面列举一些:
- 充分利用客户端的资源,比如一些客户端需要频繁访问的静态文件,像LOGO,广告图等,完全可以缓存在客户端本地。这样可以减少网络请求,加快客户端展示,还能减少服务器请求的压力。
- 我们的一些静态内容,比如新闻,博客等,在被搜索引擎爬虫抓取的时候,通过控制缓存参数,就可以减少爬虫的抓取频率,减少不必要的资源浪费。
- 如果我们的静态资源使用了CDN,那么设置了http缓存就可以在CDN节点上保存一份文件,减少CDN的回源次数,减少网络延时和源站服务器压力。
六.断点请求
1.Accept-Ranges:
服务端支持断点下载时会返回这个响应头给客户端,当客户端知道这个以后就可以发送断点请求了。
2.Content-Length:
响应信息的长度,告诉客户端当前请求返回了多少数据。这里要注意一下,用head方法提交请求时不会返回具体数据,但是这个Content-Length会返回完整数据的大小。
3.Range/Content-Range:
客户端请求时提交名为Range的header,告诉服务器自己要请求哪部分的数据。
比如:Range: bytes=0-1023表示请求第0到1023个字节.然后服务器返回这1024个字节的内容给客户端,响应头中会带上Content-Range。即:Content-Range: bytes 0-1023/4096,这个4096就是文件总大小。客户端下次请求可以从第1024个字节处开始,Range: bytes=1024-xxxx
七.编码
1.Accept-Encoding/Content-Encoding:
前者是客户端支持接收的消息编码类型。默认是identity,可选值有gzip,compress等。后者是服务器端响应信息的内容编码类型,常用的就是压缩。压缩的好处显而易见,可以大大减少网络传输的开销,相对于服务器端压缩产生的cpu消耗,网络传输的减少显然更实在。常见形式:Content-Encoding: gzip,deflate,compress.通常我们对html,js,css,xml,json之类的响应结果可以进行压缩传输。
2.Transfer-Encoding:
response header.响应消息的传输编码类型,规定了网络传输的形式。一般都是下面这种形式:Transfer-Encoding: chunked。当服务器产生动态内容,不知道响应信息的具体长度时,可以通过这个指定分块进行传输,处理多少数据就返回多少数据,这样不用等到数据都准备好了一次性返回。结合上面的内容编码,比如gzip,可以分块压缩并进行传输。另外,请注意,在使用这种编码传输时,我们是看不到Content-Length的,因为内容还没有完全生成。
八.Session和Cookie
HTTP请求是无状态的请求,但是在我们的互联网应用中,经常需要标识用户状态信息来完成一些交互性的操作,比如用户认证要记录用户登录状态,购物车应用要记住用户选择的商品,广告投放应用要记录用户的历史浏览行为等等。这里就会用到session和cookie了。
session:是指http请求-响应的过程中客户端与服务器端的交互状态,这些信息被保存在服务器端,比如内存,数据库等。每个session都有一个唯一标识,由服务器生成,这个标识也要在客户端进行保存,这样客户端在下次请求时可以带上这个标识,方便服务器判断客户端的状态。
客户端对session的支持:
通过cookie保存session id,在请求时发送给服务器。
通过url的参数携带session id与服务器通信。
通过表单的隐藏字段携带session id与服务器通信。
session共享的问题:
在分布式应用中,我们的http server一般都架在反向代理或是负载均衡设备后面,这就会面临一个session共享的问题。也就是同一个用户的多个请求可能被分发到多个不同的机器,如果我们把session保存在机器本地内存中的话,就无法在多个机器间共享用户的session。这个问题,一般来说,我们可以有两种方式来解决:
把session存放到分布式的内存(eg:memcached)或是集中式存储中(eg:database)。
在反向代理或负载均衡设备上把相同用户的请求分发到同一台机器(这里要处理好机器宕机后请求重新分配的问题)。
cookie:在客户端保持状态化信息,每个cookie内容都属于特定的域(domain)和路径(path),出于安全考虑,不同域或路径下的cookie不能共享。
会话cookie:没有指定过期时间,保存在内存,浏览器关闭后就失效。
持久cookie:指定了过期时间,保存在浏览器本地。
详细内容可以参考: http://en.wikipedia.org/wiki/HTTP_cookie
需要注意的是cookie会存在一些安全方面的问题。
九.其他
1.X-Forward-For:
request header. 用来标识用户的真实ip,特别是通过代理(正向或反向)访问服务器或是服务器在负载均衡设备后面的情况。格式:X-forward-For: client,proxy1,proxy2,…最左边的是最接近客户端的ip。
2.User-Agent:
request header.服务器用来识别客户端基本信息的请求头。一般这个在识别搜索爬虫的时候有用,某些场景下也可以用这个来做一些客户端的统计。
3.Referer:
request header.客户端访问服务器时,这个Referer来指定请求来源,比如是从哪个网站链接过来的,我们在一些统计中会经常用到这个。另外,还有一个重要的用途就是在需要资源防盗链的场景中来过滤非法的请求来源(但是,这个referer是客户端可以伪造的)。
4.Location:
response header.在301/302状态码的响应头中,都会带上这个Location头,来指示客户端用新的地址去访问需要的资源。
5.Connection:
request/response header.在http/1.1中,客户端和服务端默认都是保持连接的,也就是Connection: keep-alive.如果任何一方不想保持连接,都可以把这个值设置为close.默认情况下,客户端和服务端会保持一个长连接,这样客户端就可以用这个连接发送多次http请求,减少频繁创建连接带来的消耗。对于这个参数,在服务端可能要做更多的设置,比如连接keep-alive的时间,服务器内核的一些网络参数设置(针对tcp)。