众所周知,HTTP 是我们通过浏览器上网所使用的主要协议,全称为 Hyper Text Transfer Protocol,超文本传输协议。
HTTP 是一个无连接无状态的协议。什么意思呢?
无连接就是每次传输数据完毕就立即断开连接,这样导致的后果就是如果请求同一台服务器上的多个资源,会花费很多时间在建立连接上。解决方法是在 HTTP/1.0 版本中使用 Connection: Keep-Alive;
字段来声明这是一个长连接,这样客户端就不会主动断开连接了。在 HTTP/1.1 中默认使用长连接。
无状态就是指每次传输的数据都是各自独立的,即当前的 HTTP 连接不知道它之前和之后的 HTTP 连接的所有情况。这样也会导致一些不好的后果,比如重复传输一些数据,如用户名和密码等。解决方法是使用 cookie 和 session。所谓 cookie 就是服务器发给浏览器的一个或多个字符串,用来在服务器端唯一标示该用户,它由服务器发给客户端并存储在客户端。而 session 则存储在服务器上,也唯一标示了该用户,服务器每次把该 session 的 sessionID 发给客户端,客户端将其返回给服务器就可以。
然而使用 cookie 和 session 的缺陷就是这是一种不安全的方式。因为不管是 cookie 还是 session,不管是 GET 还是 POST 方法,数据都是在网络上明文传输的,也就是说,攻击者可以获取你的 cookie 或 session 来伪造一个 HTTP 报头,让服务器误认为就是你本人在操作。针对这种情况,解决方案是使用 HTTPS 协议,它就是在 HTTP 协议和 TCP 协议之间加了一层 SSL 协议。SSL 是一个加密协议,服务器和客户端共同持有一个公钥和私钥,分别对发送的数据进行加密和解密操作。这样数据仍然是在网络上『裸』传输的,但即使攻击者拿到数据也因为没有私钥而无法解密,这就是一种很安全的方式。
HTTP 的请求报头格式如下(HTTP/1.0 以上版本):
请求方法 URL HTTP版本号
请求头部字段
[空行]
消息正文
HTTP响应报头格式如下:
HTTP版本号 状态码 状态码的说明
响应头部字段
[空行]
响应正文
HTTP/0.9 版本的请求报头格式如下:
GET URL
响应只能回复 HTML 格式的字符串,而不能是别的内容,比如
<html>
<body>hello world!</body>
</html>
而在请求报头中的请求方法共有9种,如下:
请求方法 | 含义 | 出现于哪个版本 |
---|---|---|
GET | 获取资源,不对服务器产生其他影响 | HTTP/0.9 |
POST | 向服务器提交数据,会影响服务器 | HTTP/1.0 |
HEAD | 和GET类似,只要求返回头部信息 | HTTP/1.0 |
PUT | 上传某个资源 | HTTP/1.1 |
DELETE | 删除服务器某个资源 | HTTP/1.1 |
TRANCE | 要求服务器返回原始HTTP请求的内容,可用来调试 | HTTP/1.1 |
OPTION | 查看服务器对某个特定URL都支持哪些方法 | HTTP/1.1 |
CONNECT | 用于某些代理服务器,将连接管线化 | HTTP/1.1 |
PATCH | 对某个资源做部分修改 | HTTP/1.1 |
在这些方法中,GET、HEAD、TRANCE、OPTION 被视为安全的方法,因为他们只从服务器获得资源信息,而不对服务器做任何修改。而 POST、PUT、DELETE 和 PATCH 则影响服务器上的资源。
另一方面,GET、HEAD、OPTION、TRANCE、PUT 和 DELETE 等请求方法被认为是等幂的,即连续多次的,重复的请求和只发送一次的请求具有完全相同的结果。而 POST 方法不同,连续发送多次请求可能进一步影响服务器上的资源。
此外,Linux 提供了几个命令:HEAD,GET 和 POST。其含义与对应的同名请求方法相同,用来快速测试 web 服务器。
常见的头部信息有:
字段名称 | 含义 |
---|---|
User-Agent | 客户端用户代理 |
Accept | 客户端可接受的文档类型 |
Content-Tyep | 正文类型 |
Content-Length | 正文长度 |
Last-Modify | 最后修改时间 |
Content-Encoding | 正文数据的压缩方法 |
Set-Cookie | 传送给客户端的cookie |
该字段用来表明客户端的标识信息,比如我的 chrome 浏览器就是 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36
。所有头部字段都是这种格式,即 name: value
格式,需要说明的是,name 的冒号后面需要有一个空格,下同,这也是 HTTP 标准的一部分。
至于其他浏览器,你们可以自己去抓包查看。不再赘述。
该字段主要用来表明客户端可接受的文档类型,一般是 */*
,即可接受任意类型的文档。
该字段用来表明正文的类型。因为 HTTP 标准规定,HTTP 报文的头部信息必须是 ASCII 格式的字符串,而正文可以是任意类型的,用此字段来说明。常见的有:
这些都是预定义的类型,除了这些,厂商还可以定义自己的类型,如 application/vnd.debian.binary-package
表明是 Debian 系统的二进制数据包。
HTTP/1.0 的最大缺陷就是每个 TCP 连接只能发送一个请求,数据传送完毕,TCP连接也就关闭了。因此对于一个网页来讲,可能会有很多个资源需要获取,就需要创建很多个 TCP 连接,每次都需要三次握手四次挥手操作,效率较低。虽然可以声明 Connection: Keep-alive
,但这毕竟不是标准定义的,属于扩展定义,不能从根本上解决问题。因此在 HTTP/1.0 发布后仅半年时间,HTTP/1.1 就发布了。
HTTP/1.1 最大的变化就是默认使用持久连接,不用声明 Connection 字段。即 TCP 连接不关闭,可以被多个连接请求复用。
HTTP/1.1 还引入了管线化机制,即在同一个 TCP 连接里面,客户端可以同时发送多个请求,这样就进一步改进了 HTTP 协议的效率。
比如有两个连接请求,原来需要客户端先发送 A 请求,然后等待服务器响应 A 请求,再发送 B 请求,再等待 B 请求。在管线化里面,客户端可以先发送 A 请求,再发送 B 请求,然后等待服务器响应 A 请求和 B 请求,当然,响应顺序是不变的。
HTTP/1.1 增加了 Host 头部字段,用来指明服务器的域名。这样就可以将数据发往同一台服务器上的不同网站,为虚拟主机的兴起打下了基础。
Google 于 2009 年公布了自行研发的 SPDY 协议,也就是 HTTP/2 的前身。
HTTP/2 的特性有:二进制协议,多工,数据流,头部信息压缩,服务器推送。
截至写作本文,HTTP/3 还没有最终定稿,但总体方向已经确定。最大的变化就是抛弃长久以来使用的 TCP 协议,而改用 Google 发明的 QUIC 协议。QUIC 底层采用 UDP 作为传输层协议,目的就是通过自定义相关握手、挥手过程,拥塞控制算法等,从而大幅度提高性能。具体包括减少 RTT 次数而提升传输速度,分块传输增强抗丢包能力等。具体的 QUIC 协议以后若有时间可能会整理一下。
【完】
本文好多信息都是参考了阮一峰的博客,整理地很系统,条理清晰,十分推荐!点击这里,请阅读并背诵全文:)