0%

《计算机网络》HTTP协议

HTTP协议

HTTP协议叫做超文本传输协议,应用层协议,是基于TCP的可靠传输。

主要规定了万维网中客户端和服务器之间的通信格式,默认使用80端口。

HTTP/1.0 报文格式

HTTP/1.0 传输的字符串的utf-8编码,每行以回车换行符\r\n结束

请求报文格式

HTTP格式

分成了3个部分:

  1. 请求行

第一行就是请求行

由3部分组成,分别为:请求方法、URL以及协议版本,之间由空格分隔

请求方法包括GET、HEAD、PUT、POST、TRACE、OPTIONS、DELETE以及扩展方法,当然并不是所有的服务器都实现了所有的方法,部分方法即便支持,处于安全性的考虑也是不可用的

协议版本的格式为:HTTP/主版本号.次版本号,常用的有HTTP/1.0和HTTP/1.1

  1. 请求头

下面是常用请求头

请求头 说明
Host 接受请求的服务器地址,可以是IP:端口号,也可以是域名
User-Agent 发送请求的应用程序名称
Connection 指定与连接相关的属性,如Connection:Keep-Alive
Accept-Charset 通知服务端可以发送的编码格式
Accept-Encoding 通知服务端可以发送的数据压缩格式
Accept-Language 通知服务端可以发送的语言
  1. 请求体(可选部分)

响应报文格式

HTTP格式

分成了3个部分:

  1. 响应行

由3部分组成,分别为:协议版本,状态码,状态码描述,之间由空格分隔

状态代码为3位数字,200299的状态码表示成功,300399的状态码指资源重定向,400499的状态码指客户端请求出错,500599的状态码指服务端出错(HTTP/1.1向协议中引入了信息性状态码,范围为100~199)

下面是常见状态码

状态码 说明
200 响应成功
301 永久重定向,搜索引擎将删除源地址,保留重定向地址
302 暂时重定向,重定向地址由响应头中的Location属性指定(JSP中Forward和Redirect之间的区别),由于搜索引擎的判定问题,较为复杂的URL容易被其它网站使用更为精简的URL及302重定向劫持
304 缓存文件并未过期,还可继续使用,无需再次从服务端获取
400 客户端请求有语法错误,不能被服务器识别
403 服务器接收到请求,但是拒绝提供服务(认证失败)
404 请求资源不存在
500 服务器内部错误
  1. 响应头

与请求头部类似,为响应报文添加了一些附加信息

常见响应头部如下:

响应头 说明
Server 服务器应用程序软件的名称和版本
Content-Type 响应正文的类型(是图片还是二进制字符串)
Content-Length 响应正文长度
Content-Charset 响应正文使用的编码
Content-Encoding 响应正文使用的数据压缩格式
Content-Language 响应正文使用的语言
  1. 响应体(可选部分)

举例1

1
curl http://baidu.com -d '{"test":"你好"}'

request
例子

response
例子

举例2

1
curl http://baidu.com -d '{"test":"你好"}' -H "Content-Type: application/json"

request
例子

response
例子

HTTP/1.1

HTTP/1.1是一次重大升级,主要是实现了TCP连接复用(一个TCP连接可以发送接收多次数据,浏览器限制一个连接最多收发6次)

但是每个连接中的收发都是按照 1发–1收–2发–2收–3发–3收 依次进行的,依然具有改良空间

Transfer-Encoding分块传输

浏览器可以通过 Content-Length 的长度信息,判断出响应实体已结束

但实际应用中,有些时候实体长度并没那么好获得,例如实体来自于网络文件,或者由动态语言生成。这时候要想准确获取长度,只能开一个足够大的 buffer,等内容全部生成好再计算。但这样做一方面需要更大的内存开销,另一方面也会让客户端等更久。

所以就出现了分块传输(不是使用Content-Length来区分消息体的结束,而是使用一个 0 长度的分块表明数据已经传完,每一个块第一行表示块内容长度,第二行是块内容)

下面是nodejs写的分块传输简单例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
require('net').createServer(function(sock) {
sock.on('data', function(data) {
sock.write('HTTP/1.1 200 OK\r\n');
sock.write('Transfer-Encoding: chunked\r\n');
sock.write('\r\n');

sock.write('b\r\n');
sock.write('01234567890\r\n');

sock.write('5\r\n');
sock.write('12345\r\n');

sock.write('0\r\n'); // 表示传输完毕
sock.write('\r\n');
});
}).listen(9090, '127.0.0.1');

HTTP/2.0

  • 二进制协议(消息头固定和消息体变长,每个字段固定了含义)。HTTP/1.* 是明文字符串传输,是一个文本协议,对人友好,但是对机器不友好,解析器性能消耗大。二进制协议的解析效率超高,几乎没有解析代价;
  • 同个域名只占用一个 TCP 连接
  • 实现了TCP连接多路复用。就是一个发送请求中可以包含多个资源请求,按照 1发–1收–3发–3收 这种方式,大大节约总时间
  • 头部压缩
  • 服务端推送
  • 流量控制
  • 流优先级

WebSocket

WebSocket也是一个应用层协议,与HTTP协议平级,弥补了 HTTP/1.* 协议无法推送的不足

TCP连接复用与TCP连接多路复用

早期每个tcp链接只实现一个来回就关闭了,相当于每次铺设一个一次性的双向单车道,一辆车跑个来回就作废了

后来 HTTP/1.1 实现了TCP连接复用,再后来 HTTP/2.0 实现了TCP连接多路复用

TCP连接复用是指:一个连接可以1发–1收–1发–1收–1发–1收这种方式复用,没有TCP连接复用的则是1发–1收,然后连接关闭,接着建立连接,然后1发–1收,又断开。每个收发都是串行的,属于半双工(可以双向传送,但必须是交替进行,同一时间只能向一个方向传送),类似于双向单车道

TCP连接多路复用是指:一个连接可以2发–2收–3发–2收–4发–5收这种方式多路复用连接,并行收发。上面流程完成了9个收发,而同样是6次包传输,TCP连接复用只能完成3个收发。就是说6次包传输中,TCP连接多路复用能够请求到9个资源,而TCP连接复用只能请求到3个资源。TCP连接多路复用的实现原理一般是给每个请求标记唯一标识,服务端返回时,指定这是哪个请求的返回。类似于双向多车道




微信关注我,及时接收最新技术文章