HTTP有哪些特点

  1. 灵活可扩展

    一开始的HTTP协议比较简单,本着开放的精神只规定了报文的基本格式:请求行/响应行 + header + body,用换行分割头部字段。可以对协议的请求方式做拓展,可以对协议的头部信息作拓展,body里的格式不做限制。

  2. 可靠传输
    HTTP基于TCP/IP,自然也继承了TCP的特点。
  3. 请求 - 应答的通信模式
    该模式明确了通信双方的定位,请求方永远是主动方。
  4. 无状态
    每次收发的报文也是相互独立的,也可以说是“没有记忆的”

HTTP的实体数据

  • 内容协商

    Accept 标记客户端接受的MINE
    Content-Type 标记服务器响应的MIME

    Accept-Encoding 标记客户端接受的压缩类型
    Content-Encoding 标记服务器响应的压缩类型

    Accept-Language 标记客户端接受的自然语言
    Content-Language 标记服务器响应的自然语言

    Accept-Charset 标记客户端接受的字符集
    Content-Type ; charset=utf-8 在Content-Type后边加声明

  • 协商的权重

    上述的协商请求头accept字段,都可以加权重
    Accept: text/html; q=0.1, text/xml; q=0.9

  • 协商的结果

    Vary: Accept-Encoding, User-Agent, Accept
    服务器表明根据客户端的哪些信息得出该协商的结果内容

HTTP传大文件的方法

  • 分块传输

    Transfer-Encoding: chunked
    将大文件分块传输
    也可以用于“流式数据”,这种情况下把body数据的长度是未知的,无法在头字段给出Content-Length
    Transfer-Encoding和Content-Length两个字端是互斥的

    分块传输的编码规则:

       每个分块包含两个部分,长度头和数据块,都以CRLF结尾
       最后一个分块长度为0,数据块内容为空
    
  • 范围请求

    请求头Range:bytes=x-y,x和y都是偏移量
    响应头Accept-Range: bytes 表示可以接受范围请求
    响应头Content-Range: bytes x-y/length

    服务器收到Range字段后

    1. 检查范围是否合法,如果一个文件的大小只有100个字节,请求的范围却是300-499,那么返回416错误码表示范围请求错误
    2. 读取文件片段,返回206状态码
    3. 添加响应头Content-Range
  • 多段数据

    Range支持使用多个x-y一次性获取多个片段
    这时候需要一个特殊的MINE类型:multipart/byteranges,还需要一个boudary参数辨识分割

HTTP的连接管理

队头阻塞
因为HTTP规定报文必须是“一发一收”,这就形成了一个先进先出的“串行”队列。

为了提高速度和效率,在持久连接的基础上,HTTP1.1进一步地支持在持久连接上使用管道化(pipelining)特性。管道化允许客户端在已发送的请求收到服务端的响应之前发送下一个请求,借此来减少等待时间提高吞吐,如果多个请求能在同一个TCP分节发送的话,还能提高网络利用率

并且使用HTTP管道化还有一些限制:
1、管道化要求服务端按照请求发送的顺序返回响应(FIFO),原因很简单,HTTP请求和响应并没有序号标识,无法将乱序的响应与请求关联起来。
2、当客户端在支持管道化时需要保持未收到响应的请求,当连接意外中断时,需要重新发送这部分请求。如果这个请求只是从服务器获取数据,那么并不会对资源造成任何影响,而如果是一个提交信息的请求如post请求,那么可能会造成资源多次提交从而改变资源,这是不允许的。而不会对服务器资源产生影响的请求有个专业名词叫做幂等请求。客户端在使用管道化的时候请求方式必须是幂等请求。

因为HTTP管道化本身可能会导致队头阻塞的问题,以及上面提到的一些限制,现代浏览器默认都关闭了管道化,并且大部分服务器也是默认不支持管道化的。

所以在http1.1中,由于浏览器对同一域名tcp连接的限制(6-8个),可以利用“域名分片”来拓宽tcp的连接个数。

HTTP的的缓存控制

cache-control字段里的max-age是“生存时间”,时间的计算起点是响应报文的创建时刻(Date头字段),而不是到达客户端后开始计算。

  • 服务器缓存机制

    no-store:不允许缓存
    no-cache:在使用缓存之前需要跟服务器验证是否缓存可用
    must-revalidate:如果缓存不过期就可以继续使用,过期了还想用则需跟服务器验证

  • 浏览器缓存机制

    浏览器和服务器都可以发送带cache-control的字段
    当点击“刷新”的时候,浏览器会在请求头加一个cache-control:max-age=0,所以此时浏览器不会使用缓存
    ctrl+F5强制刷新,cache-control:no-cache,含义和max-age=0基本一样,就看后台服务器的理解。
    “前进”,“后退”,“跳转”时,不带cache-control,所以会检查缓存

  • 条件缓存

    请求头常用“if-modified-since”和“if-none-match”,响应头提供“last-modified”和“etag”
    etag时实体标签(entity tag),是资源的唯一标识,主要是解决
    修改时间在秒级之内,etag可以区分而最后修改时间无法区分
    一个文件定期更新,最后修改时间总变,但是前后文本可能并没有改变
    etag还有强弱之分,强etag要求资源在字节级别必须完全相符,弱etag的值在前面有个“W/”标记,只要求资源在语意上没有变化,但内部可能有部分发生改变(比如增减空格)

HTTP的代理服务

代理处于HTTP通信的中间位置,可以屏蔽真实客户端,也可以屏蔽真实服务器
代理最基本的功能就是负载均衡,还可以执行更多的功能
健康检查:使用“心跳”机制监控后端服务,发现有故障及时踢出“集群”
安全防护:保护后方的服务器,限制ip地址或流量,地址网络攻击和过载
加密卸载:拦截上下行数据,任意指定策略修改请求或响应
内存缓存:复用服务器缓存

  • 代理相关字段

    via:经过一个网络点,网络点将自己的主机名或域名写在via后面,并不能知道ip地址
    事实上的标准的代理头字段
    X-Forwarded-For:经过一个网络点,网络点将自己的ip追加到后面,最左侧的就是客户端的ip
    X-Real-IP:X-Forwarder-For简化版,只有发起请求和响应方的ip

  • 代理协议

    因为通过X-Forwared-For操作代理信息必须解析HTTP报文头,原本只需要简单转发消息变成先解析再修改最后再发送。
    而且在使用HTTPS通信,代理没有能力解析报文头

    The PROXY protocol是知名的代理软件HAProxy定义
    有v1和v2两个版本,v1是明文,在HTTP报文前加一行ASCII码文本
    这一行非常简单,代理服务器在HTTP报文的基础上直接增加一行,服务器直接解析第一行的PROXY行就能知道客户端信息。
    PROXY TCP4(TCP6) 请求方地址 响应方地址 请求方端口 响应方端口rn

HTTP的缓存代理

  • 代理缓存服务

    客户端的缓存只是客户端自己使用,而代理的缓存可能为非常多的用户提供,所以有限制条件“private”和“public”
    “private”表示私有的,不能共享,所以不能被代理缓存
    “public”表示公开的,谁都可以用,那么代理就可以缓存起来
    “proxy-revalidate”只要求代理的缓存过期后必须验证,客户端不必回源,客户端只需要验证到代理这个环节就ok
    “s-maxage”表示共享的缓存的生存时间,对应客户端的“max-age”的含义,如果没有该属性,代理根据“max-age”确定生存时间
    “no-transform”也是通知代理专用的属性,代理有时候会把缓存做一下优化,比如图片压缩等等,这个属性会禁止代理做这些转化

  • 客户端缓存机制

    max-stale表示接受过期了一定时间的缓存
    min-fresh表示只接受距离过期还有一定时间的缓存

  • 其他问题

    vary是内容协商的结果,同一个请求经过内容协商,可能会有不同的字符集/编码/浏览器等版本,比如vary:accept-encoding,缓存代理必须缓存不同的版本

参考:极客时间《透视HTTP协议》


一画先生
83 声望12 粉丝

我司长期招聘前端开发工程师,有意的小伙伴+vx: Mr_yihua