HTTP那些你不知道的事
HTTP是万维网的基础协议,由Tim Berners-Lee博士和他的团队在1989-1991年间创造出来,至今已经从一个只在实验室之间交换文件的早期协议进化到了可以传输图片,高分辨率视频和3D效果的现代复杂互联网协议
万维网的发明
1989年,当时在CERN工作的Tim Berners-Lee博士写了一份关于建立一个通过网络传输超文本系统的报告,这个系统起初被命名为Mesh,在随后的1990年项目实施期间被更名为万维网,它在现有的TCP和IP协议基础之上建立,由四个部分组成:
- 一个用来表示超文本文档的文本格式,超文本标记语言(HTML)
- 一个用来交换超文本文档的简单协议,超文本传输协议(HTTP)
- 一个显示(以及编辑)超文本文档的客户端,即网络浏览器,第一个网络浏览器被称为WorldWideWeb
- 一个服务器用于提供可访问的文档,即httpd的前身
HTTP在应用的早期阶段非常简单,后来被称为HTTP/0.9,有时也叫做单行(onr-line)协议。
HTTP/0.9-单行协议
- 请求由单行指令构成,以唯一可用方法GET开头,其后跟目标资源的路径
- 响应只包含响应文档本身。
HTTP/1.0-构建可扩展性
- 增加协议版本号,如 GET HTTP/1.0, POST HTTP/1.1
- 引入 header 内容,无论请求成功与否都可以添加 header,增加灵活性
- 增加 Content Type 支持,以便 http 协议传输更多更丰富的内容
HTTP/1.1-标准化的协议
- 连接可以复用,增加 keepalive 支持
- 支持 pipeline,允许在第一个应答被完全发送之前就发送第二个请求,以降低通信延迟。
- 支持分块编码技术(chunked)
- 引入额外缓存机制(基于相对时间缓存的 cache-control 头)
- 引入内容协商头(Accept-*头)
- 引入 Host 头,以便支持虚拟主机
HTTP/2-为了更优异的表现
- 不再基于纯文本,而是使用二进制(但第一次协商为了向下兼容 HTTP/1.1 依旧使用纯文本)
- 是一个复用协议。并行请求和响应在同一个链接完成
- 压缩 headers,节省传输成本
HTTP/2和HTTP/1.1不同处:
- HTTP/2是二进制协议而不是文本协议。不再可读,也不可无障碍的手动创建,改善的优化技术现在可被实施。
- 这是一个复用协议。并行的请求能在同一个链接中处理,移除了HTTP/1.x中顺序和阻塞的约束。
- 压缩了headers。因为headers在一系列请求中常常是相似的,其移除了重复和传输重复数据的成本。
- 其允许服务器在客户端缓存中填充数据,通过一个叫服务器推送的机制来提前请求。
HTTP/3
在HTTP/3中,将弃用TCP协议,改为使用基于UDP协议的QUIC协议实现。主要为了解决HTTP/2中存在的队头阻塞问题。由于HTTP/2在单个TCP连接上使用了多路复用,受到TCP拥塞控制的影响,少量的丢包就可能导致整个TCP连接上的所有流被阻塞。
QUIC(快速UDP网络连接)是一种实验性的网络传输协议
HTTP Header妙用
基于域名的虚拟主机(Host头)
通过 client 添加 Host 头以及服务端响应 Host 头,可以实现同一个服务器上提供多个网站的的场景。
例:
1 | GET /HTTP/1.1 |
内容协商
内容协商的方式为客户端请求带上 Accept 类的头,服务端会根据这个头响应客户端期望的内容以及对应的 header(header 也可能没有,而是直接返回对应期望的内容或者重定向到目标页面)。
注:实际开发中可能会用User-Agent来作为内容协商依据
常见的Accept示例:
客户端 request
accept: application/json, text/html
accept-language: zh-CN,zh;q=0.9,en;q=0.8,en-US;q=0.7
accept-encoding: br, gzip, deflete
服务端 response(可能没有直接重定向到没目标页面)
content-type: application/json
Content-Language: zh-CN
content-encoding: gzip
跨源资源共享CORS(仅浏览器)
CORS通俗译为跨域资源共享,是一种基于HTTP头的机制,该机制通过允许服务器标示除了他自己以外的其他的origin(域、协议和端口),这样浏览器可以访问加载这些资源。出于安全性,浏览器限制脚本内发起的跨源HTTP请求。 例如,XMLHttpRequest和Fetch API遵循同源策略。 这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非响应报文包含了正确CORS响应头。
跨源域资源共享(CORS)机制允许 Web 应用服务器进行跨源访问控制,从而使跨源数据传输得以安全进行。
下载文件(仅浏览器)
打开链接下载文件需要满足以下任意条件:
- content-type 非浏览器能直接支持的,或者为默认的 application/octet-stream
- 响应头中包含 Content-Disposition: attachment,无论 content-type 是什么,都将变为文件下载,如果 Content-Disposition 的值包含 filename=for.bar,则默认下载文件名为指定 filename 的值。
文件下载带进度提醒
响应头中包含 Content-Length,则客户端可以根据这个文件长度提醒下载进度
多线程下载/断点续传
服务端必须支持 Accept-Ranges 响应,大部分情况下这个值是 bytes
1 | Accept-Ranges: bytes |
客户端请求带上 Range:(unit=first byte pos)-[last byte pos]
1 | Range: bytes=0-499 |
服务端应该返回
1 | 206 Partial Content |
大数据量传输/流式传输(chunked)
对于大容量数据、动态数据、流式数据这种不可提前预知容量(content-length)的内容,应当采用 chunked 方式。它可以方便处理动态内容,以及动态维持客户端链接。客户端通常会对 chunked 进行流式处理。
缓存(通过 header 控制)
HTTP 的缓存可以针对浏览器,也可以针对中间的代理层(如 CDN 等)
- 通常只有 GET 可以被浏览器缓存,而 OPTIONS 和 HEAD 可以被 CDN 缓存(可能需要配置)
- 响应码为 200, 206, 301, 404
HTTP 协议的缓存结构
常见缓存头:
- Expires(Since HTTP/1.0)
- 本地时间到达指定时间后缓存会过期,会重新发起 HTTP 请求
- 本地时间如果不同步会影响缓存效果
例:Expires: Thu, 01 Dec 1994 16:00:00 GMT
- Last-Modified / If-Modified-Since(Since HTTP/1.0)
- 使用服务端时间,因此本地时间不同步时不影响缓存效果
- 资源未过期服务端应该返回 304 Not Modified
例:
Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT
If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT
- Etag/If-Non-Match(Since HTTP/1.1)
- 和本地时间无关,本地时间不影响缓存效果
- 资源未过期服务端应该返回 304 Not Modified
- 使用 CDN 及分布式存储的场景通常不建议使用 Etag 头
例:
ETag: “33a64df551425fcc55e4d42a148795d9f25f89d4”
If-Non-Match: “bfc13a64729c4290ef5b2c2730249c88ca92d82d”
- Cache-Control(Since HTTP/1.1)
- cache-control: max-age=3600,public
- max-age 字段表示自获取资源之后,在本地缓存多久(单位:秒)
- public/private 代表这个是公共还是私有缓存,公共缓存是可以被所有中间层缓存的,私有缓存只能在本地浏览器中缓存。包含 max-age 参数或包含 Expires 头的时候,默认为 public,否则默认 private
- no-store:不使用任何缓存,每次重新发起请求,下载最新资源
- no-cache:每次重新验证,如果服务端未更新返回 304 Not Modified
如果以上头在响应中都包含,并且客户端均支持,那么优先级如下: Cache-Control > Expires > Etag > Last-Modified
强制HTTPS
强制 HTTPS 通常有两种方案:重定向和 HSTS。
HSTS(HTTP Strict Transport Security)是一个特殊的 http header: Strict-Transport-Security: max-age=
1 | Strict-Transport-Security: max-age=31536000;includeSubDomains |
HSTS实现强制HTTPS是由内部重定向无额外请求,不支持非标准的端口
基于HTTP/1.1之上的协议
HTTP/1.1 协议可以通过升级方式使用基于 HTTP/1.1 的高级协议,如 Websocket 和 WebDAV 等等。升级方式为添加以下两个头:
- Connection: Upgrade
- Upgrade: protocols
简单图片防盗链
图片防盗链一种比较简单的防护策略是通过 Referer 头进行防护。在请求头里添加refer