HTTP
HTTP 是应用层协议
HTTP 用于客户端和服务端之间进行通信
在应用 HTTP 协议时,必定是一端为客户端,一端为服务端。其中请求资源的一端称为客户端,提供资源响应的一端为服务端。一个 HTTP 链接必定是由客户端发起的。
HTTP 是无状态协议
HTTP 协议自身不对请求和响应之间的通信状态进行保存
HTTP 使用 URI 定位资源
资源请求的方式有两种:
GET http://abc.cn/index.html HTTP/1.1
或者是:
GET /index.html HTTP/1.1 Host: abc.cn
如果不是访问资源而是对服务器本身发起请求,可以使用 * 来代替 URI。下面是一个查询 HTTP 服务器支持的 HTTP 方法种类:
OPTIONS * HTTP/1.1
HTTP 方法
所谓 HTTP 方法,就是 客户端 在请求报文中用来告知服务器自己意图的方式。HTTP 拥有的方法如下:
方法 | 作用 | 解释 |
GET | 获取资源 | 用来请求指定 URI 所表示的资源 |
POST | 传输实体主体 | 用来向服务器发送数据 |
PUT | 传输文件 | 在请求报文中包含文件内容,并保存到 URI 代表的位置 |
HEAD | 获取报文受不 | 与 GET 类似,但是不获取报文主体,只获取报文头 |
DELETE | 删除文件 | 删除 URI 所代表的资源 |
OPTIONS | 询问支持的方法 | 向服务器查询针对 URI 所代表的资源的支持方法 |
TRACE | 跟在路径 | 让服务器将之前的请求通信环回给客户端 |
CONNECT | 要求用隧道协议廉洁代理 | 要求在于代理服务器通信时建立隧道 |
持久连接
在传统的 HTTP 连接中,每次发送资源都会建立一条新的 HTTP 连接。但是对于 HTML 这样包含很多资源的页面来说,重复地建立链接会导致效率低下,增加开销,因此,HTTP/1.1 提出了持久连接的概念 :
持久连接中,只要任意一端没有明确提出断开连接,就保持 TCP 连接状态。
持久连接使得一个 HTTP 连接可以发送多个资源,从而降低了创建和销毁 HTTP 连接的开销。
管线化
与 TCP 的滑动窗口类似,持久化连接允许一个 HTTP 连接中发送多个资源,而管线化则允许在没有得到相应时就发送下一个请求。这样就允许并发发送多个请求,而不是一个一个等待相应
状态管理
HTTP 是无状态的,服务器对于每条连接的处理方式都是一样的。但是通过让客户端在请求报文中携带一些数据来表明身份,服务器就可以对不同的客户端提供不同的服务
Cookie
服务器可以在报文中使用 Set-Cookie 在客户端中储存键值对,而客户端在发送 HTTP 请求时带上这些键值对,服务器就可以识别客户端的身份。
例如在一次 HTTP 请求中,客户端先发出请求,然后服务器设置 Cookie,之后客户端就在 HTTP 请求中带上这些 Cookie:
客户端请求服务 :
GET /reader/ HTTP/1.1 Host: abc.cn
服务器在响应报文中设置 Cookie :
HTTP/1.1 200 OK Data: Thu, 12 Jul 2012... Server: Nginx <Set-Cookie: sid=1234; path=/; expires=Wed, 10-Oct-12 07:12:20 GMT> Content-Type: text/plain; charset=UTF-8
客户端在新的请求中携带 Cookie :
GET /image/ HTTP/1.1 Host: abc.cn Cookie: sid=1234
压缩传输和分块传输
HTTP 的实体部可以通过压缩再进行传输,这要求在首部指明压缩方式 :
Content-Encoding:gzip
压缩方式常用的有四种:gzip、compress、deflate(zlib)、identity(不进行编码)
在 HTTP 通信过程中,一次传输过程完成前数据是无法使用的,因此在传输大容量数据时,通过把数据进行分块,能够让浏览器逐步显示页面。这种把实体分块的功能称为 分块传输编码 (Chunked Transfer Coding)
,其中每个小块被称为一个 Chunk
多类型数据的传输
MIME 拓展中使用了一种称为 多部分对象集合 (Multipart)
的方法,用来在一次传输中容纳多份不同类型的数据。HTTP 也采用了此方法。
多对象集合包含对象如下:
MIME 类型 | 作用 |
multipart/form-data | 上传表单文件时使用 |
multipart/byteranges | 状态码 206 响应报文包含了多个范围的内容时使用 |
对于 multipart/form-data 来说,一个 POST 请求示例如下[1] :
POST /t2/upload.do HTTP/1.1 Content-Type:multipart/form-data; boundary=ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC Host: w.sohu.com --ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC Content-Disposition: form-data; name="city" Santa colo --ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC Content-Disposition: form-data;name="desc" Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... --ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC Content-Disposition: form-data;name="pic"; filename="photo.jpg" Content-Type: application/octet-stream Content-Transfer-Encoding: binary ... binary data of the jpg ... --ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC--
其中 boundary 是自定义的分割符,而每次数据的形式为 :
<上个部分数据> --分隔符 <首部字段> <CRLF> <data> --分隔符 <下个部分数据> --分隔符--
内容之间的分隔符形式为 --分隔符 ,结尾的分隔符为 --分隔符--
对于 multipart/byteranges 来说,一个响应报文的示例为 :
HTTP/1.1 206 Partial Content Date: Wed, 15 Nov 1995 06:25:24 GMT Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT Content-Length: 1741 Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES --THIS_STRING_SEPARATES Content-Type: application/pdf Content-Range: bytes 500-999/8000 ...the first range... --THIS_STRING_SEPARATES Content-Type: application/pdf Content-Range: bytes 7000-7999/8000 ...the second range --THIS_STRING_SEPARATES--
范围请求
范围请求使得客户端能够指定只传输需要的实体部分字节流,这就实现了 HTTP 协议中的断点重传,在 HTTP 中,这种只传输指定范围字节的请求称谓 范围请求 (Range Request)
一个使用范围请求的请求头例子为 :
GET /tip.jpg HTTP/1.1 Host www.abc.cn Range: bytes =5001-10000
也可以传输 5001 之后全部的内容 :
Range: bytes=5001-
从起始到 3000 和 5000-7000 的多重范围 :
Range: bytes=-3000, 5000-7000
对于多重请求,相应状态码为 206。对于多重范围,相应报文的 MIME 格式为 multipart/byteranges。如果服务器无法响应范围请求,则会返回状态吗 200 OK 和完整报文
内容协商
服务器根据请求头可以返回合适的内容,例如根据请求头选择返回中文页面或者英文页面,这一过程称谓内容协商。内容协商需求的首部字段为:
Accept
Accept-Charset
Accept-Language
Content-Language
表单数据
表单中的 enctype 规定了以何种格式向服务器发送表单内容,有三种类型:
application/x-www-urlencoded
multipart/form-data
text-plain
其中 application/x-www-urlencoded 是默认类型
GET 请求只支持 ASCII 字符集,因此,如果要发送更大字符集的内容,应使用 POST 请求
一个使用 application/x-www-urlencoded 的示例为 :
POST / HTTP/1.1 Content-Type:application/x-www-form-urlencoded Accept-Encoding: gzip, deflate Host: w.sohu.com Content-Length: 21 Connection: Keep-Alive Cache-Control: no-cache txt1=hello&txt2=world
实际上就是把 GET 中的数据放到了 Body 中,与 GET 并无二致
HTTP 状态码
状态码代表了服务器对客户端请求的处理结果,写在了相应报文的首部。响应报文可以粗略地分为五类:
类别 | 原因 | |
1xx | Informational(信息性状态码) | 接受的请求正在处理 |
2xx | Success(成功状态码) | 请求正常处理完毕 |
3xx | Redirection(重定向状态码) | 需要进行附加操作以完成请求 |
4xx | Client Error(客户端错误状态码) | 服务器无法处理请求 |
5xx | Server Error(服务器错误状态码) | 服务器处理请求出错 |
除了 2616
记载的状态码外,WebDAV 所属的 4918
和 5842
等等也定义了大量状态码。只要遵循状态码类别的定义,即使改变 2616
定义的状态码,或者是自行创建状态码都是允许的。尽管如此,HTTP 常用的状态码只有 14 种:
状态码 | 含义 |
200 OK | 客户端发送的请求被正常处理了 |
204 No Content | 请求被正常处理,但是响应报文中不含实体的主体部分。一般发生在只需要从客户端发送信息的情况下 |
206 Partial Content | 客户端发送的范围请求被正确处理 |
301 Moved Permanently | 永久重定向。请求的资源被分配了新的 URI |
302 Found | 临时重定向。请求的资源被分配了新的 URI |
303 See Other | 与 302 类似。但是 303 要求客户端应当使用 GET 方法获取资源 |
304 Not Modified | 304 实际上和重定向无关。在未满足请求报文中的附带条件[2] 时,响应报文不包含实体部 |
307 Temporary Redirect | 与 302 相同,但是要求不将 POST 变成 GET |
400 Bad Request | 请求报文中出现语法错误。此状态码在浏览器中视同 200 OK |
401 Unauthorized | 表示发送的请求需要有通过 HTTP 认证的认证信息。如果已经进行过一次认证,表明认证失败 |
403 Forbidden | 表示对请求资源的访问被服务器拒绝了。理由 可 写在实体部 |
404 Not Found | 服务器无法找到请求的资源。也可能是服务器拒绝请求并且不想说明理由 |
500 Internal Server Error | 服务器在执行请求时发生了错误。也可能是服务器的 Bug 或者某些临时故障 |
503 Service Unavailable | 服务器超负载或者正在停机维护,现在无法响应请求 |
实际上,很多浏览器将 301、302 视同 303 进行处理,尽管 301、302 不允许将 POST 改为 GET |
协同技术
服务器还催生了一些其它技术。例如虚拟主机、代理、隧道等。
虚拟主机:将多个域名映射到一台主机上,然后服务器根据请求报文中的 Host 将请求转发给对应的网站处理。这样就可以使用一台主机搭建多个 Web 站点。
代理:代理服务器充当中间人,将客户端的请求发送给服务器,然后将服务器的响应报文发给客户端。如果在转发过程中没有更改报文,那么称为 透明代理 。如果代理会预缓存资源,那么称为 缓存代理
网关:网关与代理类似,但是网关能将使服务器提供非 HTTP 协议服务。例如在客户端和网关之间进行加密等。
隧道:隧道按要求建立一条与其它服务器的通信链路,从而保障通信的安全性
HTTPS
相比 HTTP 通过 TCP 发送报文而言,HTTPS 通过 SSL 发送报文。而 SSL 提供了双端加密。
SSL 是应用层协议,而不是运输层协议。SSL 使用 TCP 作为运输层协议
在 SSL 的通信过程中。SSL 首先使用非对称加密来构建传输通道,然后双方约定对称加密密码,并使用对称密码来传输内容。之所以如此,是因为非对称加密安全性高但是加密解密慢,而对称加密安全性低,却加密解密快。
在 HTTPS 通信过程中,首先双方交换公钥,然后再进行 SSL 加密过程。具体流程为[3] :
另外如图所示的一点是数字证书不仅包含了公钥,还包含了其它信息。在申请数字证书的时候会同时发放证书和密钥。客户端根据系统储存的根证书来验证服务器的证书是否是有效证书
身份认证
HTTP/1.1 使用的认证方式有四种:
BASIC 认证(基本认证)
DIGEST 认证(摘要认证)
SSL 客户端认证
FormBase 认证(基于表单认证)
BASIC 认证
BASIC 认证是最简单的一种认证方式,用户名和密码以 Base64 的格式进行编码后直接发送到服务器,而且没有注销操作。一次 BASIC 认证的流程为:
客户端发送请求报文
服务器发现请求的资源需要认证,然后返回带有 WWW-Authenticate 字段的 401 响应报文 :
HTTP/1.1 401 Authorization Required ... WWW-Authenticate: Basic realm="Input Your ID and Password."
客户端将用户名和密码使用冒号连接后使用 Base64 进行编码并直接发送给服务器 :
GET /private/ HTTP/1.1 Host: abc.cn Authorization: Basic Z3Vlc3Q6Z3Vlc3Q
服务器进行验证。如果通过验证直接发送包含请求资源的报文,否则返回状态码 401
DIGEST 认证
DIGEST 的认证流程为:
客户端请求资源
服务器发现资源需要认证,返回质询码
客户端使用质询码计算出来响应码,然后发送给服务器
服务器进行验证
其中第二步的响应报文格式如下 :
HTTP/1.1 401 Authorization Required WWW.Authorization: Digest realm="DIGEST"" nonce="MOSQZ0itBAA=44abb",algorithm=MD5,qop="auth"
其中 nonce 是服务器生成的质询码,内容是随机的。
第三步的格式为 :
GET /digest/ HTTP/1.1 Host: abc.cn Authorization: Digest username="guest".realme="DIGEST" nonce="...",uri="/digest/",algorithm=MD5 responce="...",qop=auth,nc=00000001,cnonce="082c875dcb2ca740"
SSL 客户端认证
SSL 的认证步骤为[4] :
SSL 只保证了通信双端是可信双端,保证了通信过程是安全的,但是对于身份验证是无用的,服务器依然需要使用其它认证方式来将用户和数据库中的信息进行匹配。
这里和 ssh 不同,ssh 使用公钥和密钥匹配来同时完成加密和认证。但是 HTTPS 只是使用公钥来完成加密过程。 |
基于表单的认证
基于表单认证的方式并不是 HTTP 定义的一种方式,其根本原因是 BASIC 和 DIGEST 都无法满足变化多样的需求环境。目前大部分网站使用的认证都是基于表单的认证。
在表单认证中,客户端将表单数据(比如帐号和密码)发送给服务器,然后服务器完成验证,之后通过 Set-Cookie 来完成身份识别。
表单验证的方式是使用 Cookie 管理 Session,其中使用 Set-Cookie 设置的就是 Session ID
Session 是站在服务端看的。当用户第一次完成认证时,服务器为客户端创建一个 Session 对象,然后将 Session ID 使用 Set-Cookie 发送给客户端,此后服务器依据客户端 Cookie 中的 Session ID 来找到对应的 Session,并使用特定的 Session 服务特定的客户端
Session 和 Cookie 的组合在无状态的 HTTP 协议上实现了状态管理
WebSocket
HTTP 无法妥善处理实时更新的任务,这主要体现在:
一条链接只能发送一个请求
请求只能从客户端发起。客户端不接受响应以外的指令
请求/响应首部不可压缩
可能会重复发送相同的首部
数据压缩及压缩格式是可选的
Ajax 通过使用 XMLHttpRequest API 和 DOM 局部更新页面可以在一定上解决问题,但是会导致大量请求产生,依然无法解决问题。因此 WebSocket 应运而生
WebSocket over HTTP,但是相比 HTTP,WebSocket 具有以下特点:
链接一旦建立就保持连接
WebSocket 是全双工的
请求依然是从客户端发起,但是由于连链接是保持的,而 WebSocket 又是全双工的,因此服务器可以在数据更新后主动将数据发送给客户端。而客户端不需要再轮询
要使用 WebSocket,需要在请求报文首部加入 Upgrade: websocket 首部 :
GET /chat HTTP/1.1 Host: abc.cn Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ Origin: http://example.com Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13
而请求报文需要返回 101 Switching Protocols :
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= Sec-WebSocket-Protocol: chat
Web 攻击技术
最简单的攻击方式是拦截并修改 HTTP 请求和响应报文,对于 HTTPS 而言,如果客户端引入了不安全的证书,那么 HTTPS 也可以被任意修改。
另外还有 SQL 注入、OS 命令注入、HTTP 首部注入、目录遍历攻击等,这些攻击方式都是因为服务器对转义字符处理不正确导致的。