一、What is HTTP ?
1. 协议概述
HTTP
(HyperText Transfer Protocol,超文本传输协议) 是互联网上应用最为广泛的一种网络协议,设计 HTTP
最初的目的是为了提供一种发布和接收HTML页面的方法
HTTP
协议中现今广泛使用的一个版本是1999年6月公布的 HTTP1.1
,而2015年5月发表的HTTP/2
取代 HTTP1.1
成为 HTTP
新的实现标准
通常,由 HTTP
客户端发起一个请求,创建一个到服务器指定端口(默认是80端口
)的 TCP
连接。HTTP
服务器则在那个端口监听客户端的请求。一旦收到请求,服务器会向客户端返回一个状态,比如 HTTP/1.1 200 OK
,以及返回的内容,如请求的文件、错误消息、或者其它信息
二、请求信息 (Request Message)
发出的请求信息包括以下几个:
- 请求行
例如GET /images/logo.gif HTTP/1.1
,表示从/images
目录下请求logo.gif
这个文件 - 请求头
例如Accept-Language: en
- 空行
- 其他消息体
请求行和标题必须以<CR><LF>作为结尾
空行内必须只有<CR><LF>而无其他空格
在HTTP/1.1协议中,所有的请求头,除Host外,都是可选的
1. 请求方法
HTTP/1.1
中共定义了8种方法(动作)来以不同方式操作指定的资源
-
GET
:向指定的资源发出“显示”请求,使用GET
方法应该只用在读取数据 -
POST
:向指定资源提交数据,请求服务器进行处理(例如提交表单或者上传文件)
数据被包含在请求本文中。这个请求可能会创建新的资源或修改现有资源,或二者皆有 -
HEAD
:与GET
方法一样,都是向服务器发出指定资源的请求
只不过服务器将不传回资源的本文部分。它的好处在于,使用这个方法可以在不必传输全部内容的情况下,就可以获取其中“关于该资源的信息”(元信息或称元数据) -
OPTIONS
:这个方法可使服务器传回该资源所支持的所有HTTP
请求方法。
用'*'来代替资源名称,向Web服务器发送OPTIONS
请求,可以测试服务器功能是否正常运作 -
PUT
:向指定资源位置上传其最新内容 -
DELETE
:请求服务器删除Request-URI
所标识的资源 -
TRACE
:回显服务器收到的请求,主要用于测试或诊断 -
CONNECT
:HTTP/1.1
协议中预留给能够将连接改为管道方式的代理服务器。
通常用于SSL
加密服务器的链接(经由非加密的HTTP
代理服务器)
** 方法名称是区分大小写的 **:
- 当某个请求所针对的资源不支持对应的请求方法的时候,服务器应当返回状态码
405(Method Not Allowed)
- 当服务器不认识或者不支持对应的请求方法的时候,应当返回状态码
501(Not Implemented)
- HTTP服务器至少应该实现
GET
和HEAD
方法,其他方法都是可选的- 安全超文本连接协议使用
https://
代替http://
2. 状态码
所有HTTP响应的第一行都是状态行,依次是当前 HTTP
版本号,3位数字组成的状态代码,以及描述状态的短语,彼此由空格分隔。
状态代码的第一个数字代表当前响应的类型:
-
1xx
消息 —— 请求已被服务器接收,继续处理 -
2xx
成功 —— 请求已成功被服务器接收、理解、并接受 -
3xx
重定向 —— 需要后续操作才能完成这一请求 -
4xx
请求错误 —— 请求含有词法错误或者无法被执行 -
5xx
服务器错误 —— 服务器在处理某个正确请求时发生错误
3. 举个栗子
客户端请求:
GET / HTTP/1.1
Host:
末尾有一个空行
第一行:指定方法、资源路径、协议版本
第二行:在1.1版里必带的一个header作用指定主机
服务器响应:
HTTP/1.1 200 OK
Content-Length: 3059
Server: GWS/2.0
Date: Sat, 11 Jan 2003 02:44:04 GMT
Content-Type: text/html
Cache-control: private
Set-Cookie: PREF=ID=73d4aef52e57bae9:TM=1042253044:LM=1042253044:S=SMCc_HRPCQiqy
X9j; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/;
Connection: keep-alive
(紧跟着一个空行,并且由HTML格式的文本组成了Google的主页)
- 在
HTTP1.0
,单一TCP
连接内仅执行一个“客户端发送请求—服务器发送应答”周期,之后释放TCP
连接。 - 在
HTTP1.1
优化支持持续活跃连接:客户端连续多次发送请求、接收应答;批量多请求时,同一TCP
连接在活跃Keep-Live
间期内复用,避免重复TCP
初始握手活动,减少网络负荷和响应周期。此外支持应答到达前继续发送请求(通常是两个),称为“流线化”(stream)。
4. 通用头域
通用头域包含请求和响应消息都支持的头域,通用头域包含:
-
Cache-Control
头域:指定请求和响应遵循的缓存机制
在请求消息或响应消息中设置Cache-Control
并不会修改另一个消息处理过程中的缓存处理过程 -
请求时的缓存指令包括:
-
no-cache
:指示响应可被任何缓存区缓存 -
no-store
:在请求消息中发送将使得请求和响应消息都不使用缓存,可防止重要的信息被无意的发布 -
max-age
:指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应 -
max-stale
:指示客户机可以接收超出超时期间的响应消息。
如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息 -
min-fresh
:指示客户机可以接收响应时间小于当前时间加上指定时间的响应 only-if-cached
-
-
响应消息中的指令包括:
-
public
:指示响应可被任何缓存区缓存 private
no-cache
no-store
no-transform
must-revalidate
proxy-revalidate
max-age
-
-
Connection
-
DateDate
头域:头域表示消息发送的时间,时间的描述格式由rfc822定义 -
例如,
Date:Mon,31Dec200104:25:57GMT
-
Date
描述的时间表示世界标准时,换算成本地时间,需要知道用户所在的时区。 -
Pragma
头域:用来包含实现特定的指令 -
最常用的是
Pragma:no-cache
-
在 HTTP/1.1 协议中,它的含义和
Cache- Control:no-cache
相同 -
Transfer-Encoding
头域 -
Upgrade
头域 -
Via
头域
上面总结的是“通用头域”,我们先来看下一个典型的请求信息:
GET / HTTP/1.1
Host:
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.103 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
Cookie: BDUSS=aaaaa; BAIDUID=bbbbb:FG=1; PSTM=1459694957; BDRCVFR[loys_9vxHFf]=mk3SLVN4HKm; BIDUPSID=ccccc; pgv_pvi=9192257536; pgv_si=s6465831936; H_PS_PSSID=ddddd
上面的第一行表示HTTP客户端(可能是浏览器、下载程序)通过GET方法获得指定URL下的文件。接下来,我们来分析下“ 请求头域 ”
5. 请求头域
-
Host
头域:指定请求资源的Intenet主机和端口号 - 必须表示请求url的原始服务器或网关的位置
- HTTP/1.1请求必须包含主机头域,否则系统会以400状态码返回
-
Referer
头域:允许客户端指定请求uri的源资源地址 - 这可以允许服务器生成回退链表,可用来登陆、优化cache等
- 也允许废除的或错误的连接由于维护的目的被追踪
- 如果请求的uri没有自己的uri地址,Referer不能被发送
- 如果指定的是部分uri地址,则此地址应该是一个相对地址
-
Range
头域:请求实体的一个或者多个子范围 - 例如
- 表示头500个字节:bytes=0-499
- 表示第二个500字节:bytes=500-999
- 表示500字节以后的范围:bytes=500-
- 第一个和最后一个字节:bytes=0-0,-1
- 同时指定几个范围:bytes=500-600,601-999
- 但是服务器可以忽略此请求头,如果无条件
GET
包含Range
请求头,响应会以状态码206(PartialContent)
返回而不是以200 (OK)
-
User-Agent
头域:内容包含发出请求的用户信息
三、响应消息(Response Message)
1. 响应头
我们先来看一个“请求百度首页”的响应头:
HTTP/1.1 200 OK
Date: Sun, 03 Apr 2016 15:44:32 GMT
Content-Type: text/html;charset=utf-8
Transfer-Encoding: chunked
Connection: Keep-Alive
Cache-Control: private
Expires: Sun, 03 Apr 2016 15:44:32 GMT
Content-Encoding: gzip
Server: BWS/1.1
X-UA-Compatible: IE=Edge,chrome=1
BDPAGETYPE: 2
BDQID: 0xb2584dee0005f8ac
BDUSERID: 801624962
Set-Cookie: BDSVRTM=147; path=/
Set-Cookie: BD_HOME=1; path=/
Set-Cookie: H_PS_PSSID=aaaaa; path=/;
-
响应头的第一行为右边的格式:
HTTP-Version Status-Code Reason-Phrase
-
HTTP- Version
:表示支持的HTTP版本
例如为HTTP/1.1 -
Status- Code
:是一个三个数字的结果代码(可参考前面总结的“状态码”部分)
主要用于机器自动识别,第一个数字定义响应的类别 -
Reason-Phrase
:给Status-Code
提供一个简单的文本描述
主要用于帮助用户理解 -
Location
响应头:用于重定向接收者到一个新URI地址 -
Server
响应头:包含处理请求的原始服务器的软件信息。
此域能包含多个产品标识和注释,产品标识一般按照重要性排序
2. 实体
请求消息 和 响应消息 都可以包含实体信息,实体信息一般由 实体头域 和 实体 组成
实体头包括:
Allow | Content- Base | Content-Encoding | |
Content-Language | Content-Length | Content-Location | |
Content-MD5 | Content-Range | Content-Type | |
Etag | Expires | Last-Modified | |
extension-header |
-
Content-Type
实体头:向接收方指示实体的介质类型 - 指定
HEAD
方法送到接收方的实体介质类型 - 或
GET
方法发送的请求介质类型 -
Content-Range
实体头:指定整个实体中的一部分的插入位置,也指示了整个实体的长度 - 在服务器向客户返回一个部分响应,它必须描述响应覆盖的范围和整个实体长度
- 一般格式:
Content-Range:bytes-unit first-byte-pos-last-byte-pos/entity-legth
- 例如,传送头500个字节次字段的形式:
Content-Range:bytes0- 499/1234
-
Content-Range
表示传送的范围,Content-Length
表示实际传送的字节数 -
Last-modified
实体头:指定服务器上保存内容的最后修订时间
3. 响应头
-
Allow
:服务器支持哪些请求方法(如GET
、POST
等) -
Content-Encoding
:文档的编码(Encode)方法 -
只有在解码之后才可以得到
Content-Type
头指定的内容类型 -
利用
gzip
压缩文档能够显著地减少HTML
文档的下载时间 -
Java的
GZIPOutputStream
可以很方便地进行gzip
压缩,但只有Unix上的Netscape
和Windows
上的IE 4、IE 5才支持它。 -
因此,
Servlet
应该通过查看Accept-Encoding
头(即request.getHeader("Accept- Encoding")
)检查浏览器是否支持gzip
,为支持gzip
的浏览器返回经gzip
压缩的HTML
页面,为其他浏览器返回普通页面。 -
Content-Length
:表示内容长度 -
只有当浏览器使用持久HTTP连接时才需要这个数据
-
Content-Type
:表示后面的文档属于什么MIME类型 -
Servlet
默认为text/plain
,但通常需要显式地指定为text/html
-
由于经常要设置
Content-Type
,因此HttpServletResponse
提供了一个专用的方法setContentTyep
-
Date
:当前的GMT时间 -
你可以用
setDateHeader
来设置这个头以避免转换时间格式的麻烦。 -
Expires
:应该在什么时候认为文档已经过期,从而不再缓存它? -
Last-Modified
:文档的最后改动时间。 -
客户可以通过
If-Modified-Since
请求头提供一个日期,该请求将被视为一个条件GET
,只有改动时间迟于指定时间的文档才会返回,否则返回一个304(Not Modified)
状态。 -
Last-Modified
也可用setDateHeader方法来设置。 -
Location
:表示客户应当到哪里去提取文档 -
Location
通常不是直接设置的,而是通过HttpServletResponse
的sendRedirect
方法,该方法同时设置状态代码为302
。 -
Refresh
:表示浏览器应该在多少时间之后刷新文档,以秒计 -
但是,对于
Servlet
来说,直接设置Refresh
头更加方便 -
注意
Refresh
的意义是“N秒之后刷新本页面或访问指定页面”,而不是“每隔N秒刷新本页面或访问指定页面”。 -
因此,连续刷新要求每次都发送一个
Refresh
头,而发送204
状态代码则可以阻止浏览器继续刷新,不管是使用Refresh
头还是<META HTTP-EQUIV="Refresh" ...>
-
注意:
Refresh
头不属于HTTP 1.1
正式规范的一部分,而是一个扩展,但Netscape
和IE
都支持它 -
Server
:服务器名 -
Servlet
一般不设置这个值,而是由Web
服务器自己设置 -
Set-Cookie
:设置和页面关联的Cookie -
Servlet
不应使用response.setHeader("Set-Cookie", ...)
,而是应使用HttpServletResponse
提供的专用方法addCookie
四、Cookie
某些网站为了辨别用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)
1. 分类
Cookie
总是保存在客户端中,按在客户端中的存储位置可分为
内存Cookie
-
内存Cookie
由浏览器维护,保存在内存中,浏览器关闭后就消失了,其存在时间是短暂的 硬盘Cookie
-
硬盘Cookie
保存在硬盘里,有一个过期时间,除非用户手工清理或到了过期时间,硬盘Cookie
不会被删除,其存在时间是长期的
所以,按存在时间,可分为 非持久Cookie
和 持久Cookie
2. 用途
因为 HTTP
协议是无状态的,即服务器不知道用户上一次做了什么,这严重阻碍了交互式 Web
应用程序的实现。Cookie就是用来绕开 HTTP
的无状态性的“额外手段”之一。服务器可以设置或读取 Cookies
中包含信息,借此维护用户跟服务器会话中的状态
3. 应用场景:
- 当登录一个网站时,网站往往会请求用户输入用户名和密码,并且用户可以勾选“下次自动登录”
- 如果勾选了,那么下次访问同一网站时,用户会发现没输入用户名和密码就已经登录了
- 这正是因为前一次登录时,服务器发送了包含登录凭据(用户名加密码的某种加密形式)的
Cookie
到用户的硬盘上 - 第二次登录时,(如果该
Cookie
尚未到期)浏览器会发送该Cookie
,服务器验证凭据,于是不必输入用户名和密码就让用户登录了
4. Cookie的缺陷
-
Cookie
会被附加在每个HTTP
请求中,所以无形中增加了流量 - 由于在HTTP请求中的
Cookie
是明文传递的,所以安全性成问题(除非用HTTPS
) -
Cookie
的大小限制在4KB左右。对于复杂的存储需求来说是不够用的
5. 识别功能
- 如果在一台计算机中安装多个浏览器,每个浏览器都会以独立的空间存放
Cookie
- 因为
Cookie
中不但可以确认用户信息,还能包含计算机和浏览器的信息,所以一个用户使用不同的浏览器登录或者用不同的计算机登录,都会得到不同的Cookie
信息 - 另一方面,对于在同一台计算机上使用同一浏览器的多用户群,
Cookie
不会区分他们的身份,除非他们使用不同的用户名登录。