透视HTTP协议-进阶篇-极客时间-学习笔记

HTTP头部实体

HTTP协议报文是按照header+body的形式,其中body传输的时候是二进制文件,但具体按照什么格式来读取,必须有所约定。就像一个文件,我们改变不同的后缀名,打开完全是不一样的。

报文格式借鉴了电子邮件系统的MIME,“多用途互联网邮件扩展”(Multipurpose Internet Mail Extensions)。

常见的分为下列几种:

text,文本格式的可读数据,比如text/html,text/plain,text/css;

image,图像数据,image/gif,image/jpeg;

audio/video,音视频数据,audio/mpeg,video/mp4;

application,数据格式不固定,可以是文本也可以是二进制数据。application/json,application/javascript,application/pdf。

还有一个编码方式encoding type,选择body体的压缩方式:

gzip:GNU zip 压缩格式,也是互联网上最流行的压缩格式;

deflate:zlib(deflate)压缩格式,流行程度仅次于 gzip;

br:一种专门为 HTTP 优化的新压缩算法(Brotli)。

这样,客户端用Accept,Accept-Encoding来说明可以接受的内容和编码方式;服务端用Content-Type,Content-Encoding来解释最终选择发送的格式和编码方式。

如果请求报文里没有 Accept-Encoding 字段,就表示客户端不支持压缩数据;如果响应报文里没有 Content-Encoding 字段,就表示响应数据没有被压缩。

我们书写的代码都是用英文书写,但客户端那边的使用者可能是各个国家,所以存在一个语言问题。Accept-language就是记录这个。与语言对应的是不同语言的字符集charset。

现在的浏览器都支持多种字符集,通常不会发送 Accept-Charset,而服务器也不会发送 Content-Language。在请求头里一般只会有 Accept-Language 字段,响应头里只会有 Content-Type 字段。对应我自己实验的现象,客户端只是提出请求语言,然后客户端回复UTF-8统一编码即可,然后再交给客户端来自行转换成需求语言。

响应头里没有对应的 Content-Charset,而是在Content-Type字段的数据类型后面用“charset=xxx”来表示。

在 HTTP 协议里用 Accept、Accept-Encoding、Accept-Language 等请求头字段进行内容协商的时候,还可以用一种特殊的“q”参数表示权重来设定优先级,这里的“q”是“quality factor”的意思。

权重的最大值是 1,最小值是 0.01,默认值是 1,如果值是 0 就表示拒绝。具体的形式是在数据类型或语言代码后面加一个“;”,然后是“q=value”。

这样给服务器一些可回复的选择,对应服务器对于内容协商的过程是不透明的,每个 Web 服务器使用的算法都不一样。最后会给出一个Vary参数,记录服务器在内容协商时参考的请求头字段。

HTTP协议并不属于强制性的要求,所以其实客户端发过去的头文件描述的请求,返回报文并不一定按要求返回。比如我自己实验的几个网站,发现请求的Accept-Language是zh,但返回的Content-Type是***,charset=UTF-8。我理解等于无论要求的是什么语言,服务器统一用UTF-8回复,这样再由服务器来进行处理。

 

如何在有限带宽下高效传输大文件,将大文件直接传输会把网络带宽完全抢占,这也是我们以前经常说起的,下载抢网速的原因。

数据压缩,与之前请求头的Accept-Encoding有关,但此类压缩一般都是对文本类的压缩有效,像音视频这类原本就已经压缩的文件,再次压缩的效果并不好。

除了数据压缩外,另一个思路就是人为的将大文件进行切割,变成一系列的小文件后再来传输,这样更小的层面来说就是传输小文件了,再浏览器这端再把数据包组合成大文件,叫做分块传输,chunked(HTTP/2.0已经不支持)。对应响应报文里用头字段“Transfer-Encoding: chunked”来表示,意思是报文里的 body 部分不是一次性发过来的,而是分成了许多的块(chunk)逐个发送。

“Transfer-Encoding: chunked”和“Content-Length”这两个字段是互斥的,也就是说响应报文里这两个字段不能同时出现,一个响应报文的传输要么是长度已知,要么是长度未知(chunked)。

分块传输的规格如下:

  1. 每个分块包含两个部分,长度头和数据块;
  2. 长度头是以 CRLF(回车换行,即\r\n)结尾的一行明文,用 16 进制数字表示长度;
  3. 数据块紧跟在长度头后,最后也用 CRLF 结尾,但数据不包含 CRLF;
  4. 最后用一个长度为 0 的块表示结束,即“0\r\n\r\n”。

分块传输并不是分为多个HTTP响应报文,而是类似“长连接”的效果,body部分的报文是分块发送。

范围请求,是类似我们看视频跳过片头,只截取文件的部分进行传输。

范围请求不是 Web 服务器必备的功能,可以实现也可以不实现,如果支持该功能,服务器必须在响应头里使用字段“Accept-Ranges: bytes”明确告知。而如果不支持,则发送“Accept-Ranges: none”,或者干脆不发送“Accept-Ranges”字段。

请求头Range是 HTTP 范围请求的专用字段,格式是“bytes=x-y”,其中的 x 和 y 是以字节为单位的数据范围。要注意 x、y 表示的是“偏移量”,从 0 计数。这里的数据范围是指原数据的,如果是压缩文件,客户端没有办法掌握压缩后的数据范围和目标数据范围之间的偏差。

假设文件是 100 个字节,那么:

“0-”表示从文档起点到文档终点,相当于“0-99”,即整个文件;

“10-”是从第 10 个字节开始到文档末尾,相当于“10-99”;

“-1”是文档的最后一个字节,相当于“99-99”;

“-10”是从文档末尾倒数 10 个字节,相当于“90-99”。

服务器收到 Range 字段后,需要做四件事。

第一,它必须检查范围是否合法。类似数组索引,不能超出界限;

第二,如果范围正确,服务器就可以根据 Range 头计算偏移量,读取文件的片段了,返回状态码“206 Partial Content”表示 body 只是原数据的一部分;

第三,服务器响应包含头字段Content-Range,告诉片段的实际偏移量和资源的总大小,格式是“bytes x-y/length”;

第四,直接把片段用 TCP 发给客户端,一个范围请求就算是处理完了。

可以通过该方式实现多段下载,每段用不同的线程来执行。

范围请求甚至可以在一个HTTP请求中申请多段数据,在Range中用“,”分开,对应的响应报文Content-Type设置类型:“multipart/byteranges”再加上参数“boundary=xxx”给出段之间的分隔标记。

每个分段要用‘--’+分隔标记+CRLF开头,然后加上两个响应头Content-Type(不同与整个报文的Content-Type,是真实的具体类型)和Content-Range。多段数据结束的地方还需要用‘--’+分隔标记+‘--’+CRLF来标示。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值