HTTP笔记

1 基础篇

1.1 定义

HTTP,英文全称为 HyperText Transfer Protocol,翻译过来就是 超文本传输协议。

HTTP 是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据约定和规范。

我们将这句话按 协议、传输、超文本 拆分开来理解,得到以下内容:

协议

HTTP 是一个用在计算机世界里的协议,它确立了一种计算机之间交流通信的规范,以及相关的各种控制和错误处理方式。

传输

HTTP 专门用来在两点之间传输数据,不能用于广播、寻址或路由。

超文本

HTTP 传输的是文字、图片、音频、视频等超文本数据。

1.2 HTTP报文

报文结构

HTTP 协议的请求报文和响应报文的结构基本相同,由三大部分组成:

  1. 起始行(start line):描述请求或响应的基本信息;

  2. 头部字段集合(header):使用 key-value 形式更详细地说明报文;

  3. 消息正文(entity/body):也叫"实体",实际传输的数据,它不一定是纯文本,可以是图片、视频等二进制数据。

HTTP 协议规定报文必须有 header,但可以没有 body,而且在 header 之后必须要有一个“空行”,也就是“CRLF”,十六进制的“0D0A”。

所以,一个完整的 HTTP 报文就像是下图的这个样子,注意在 header 和 body 之间有一个“空行”。我们可以想象一下,起始行对应的是小人的头发,头部对应的是小人的头,空行对应的是小人的脖子,实体对应的是小人的身体。是不是还挺好记的

HTTP笔记
看看下面这张没有 body 的图,理解会更深刻一点。
HTTP笔记

起始行

因为请求报文和响应报文的起始行有一定区别,所以我们分开介绍。

请求行

HTTP 请求报文里的起始行,也称请求行,它简要地描述了客户端想要如何操作服务器端的资源

举个栗子:

GET / HTTP/1.1

我们拆开来看,请求行由三部分构成:

  1. 请求方法:是一个动词,如 GET/POST,表示对资源的操作;
  2. 请求目标:通常是一个 URI,标记了请求方法要操作的资源;
  3. 版本号:表示报文使用的 HTTP 协议版本。

这三个部分通常使用空格(space)来分隔,最后要用 CRLF 换行表示结束。
HTTP笔记

状态行

HTTP 响应报文里的起始行,不叫响应行,而叫状态行,意思是服务器响应的状态。

举个栗子

HTTP/1.1 200 OK

我们发现,状态行同样有三部分组成:

  1. 版本号:表示报文使用的 HTTP 协议版本;
  2. 状态码:一个三位数,用代码的形式表示处理的结果,比如 200 是成功,500 是服务器错误;
  3. 原因:作为数字状态码补充,是更详细的解释文字,帮助人理解原因。
    HTTP笔记

头部字段

如下图,我们可以看到请求头响应头
HTTP笔记HTTP笔记
请求头和响应头的结构基本是一样的,所以我把请求头和响应头里的字段放在一起介绍。

头部字段是 key-value 的形式,key 和 value 之间用“:”分隔,最后用 CRLF 换行表示字段结束。比如在“Host: 127.0.0.1”这一行里 key 就是“Host”,value 就是“127.0.0.1”。

使用头字段需注意以下几点:

  • 字段名不区分大小写;
  • 字段名里不允许出现空格,可以使用连字符“-”,但不能使用下划线“_”;
  • 字段名后面必须紧接着“:”,不能有空格,而“:”后的字段值前可以有多个空格;
  • 字段的顺序是没有意义的,可以任意排列不影响语义;
  • 字段原则上不能重复,除非这个字段本身的语义允许,例如 Set-Cookie。

实体

就是具体的数据了,也就是body部分。请求报文对应请求体, 响应报文对应响应体。

1.3 HTTP请求方法

对请求方法的理解

请求方法是客户端发出的、要求服务器执行的、对资源的一种操作;请求方法是对服务器的“指示”,真正应如何处理由服务器来决定;

有什么请求方法

目前 HTTP/1.1 规定了八种方法,单词都必须是大写的形式

  1. GET:获取资源,可以理解为读取或者下载数据;

  2. HEAD:获取资源的元信息;

  3. POST:向资源提交数据,相当于写入或上传数据;

  4. PUT:类似 POST;

  5. DELETE:删除资源;

  6. CONNECT:建立特殊的连接隧道;

  7. OPTIONS:列出可对资源实行的方法;

  8. TRACE:追踪请求 - 响应的传输路径。

GET 和 POST 有什么区别

GET 在浏览器回退时是无害的,而 POST 会再次提交请求;

GET 请求会被浏览器主动缓存,而 POST 不会,除非手动设置;

GET 请求参数会被完整保留在浏览器历史记录里,而 POST 中的参数不会被保留;

GET 请求在 URL 中传送的参数是有长度限制的,而 POST 没有限制;

GET 参数通过 URL 传递,POST 放在 Request body 中。

1.4 HTTP 响应状态码

状态码在响应报文里表示了服务器对请求的处理结果;状态码是十进制的三位数,分为五类,从 100 到 599;这五类的具体含义是:

  • 1××:提示信息,表示目前是协议处理的中间状态,还需要后续的操作;

  • 2××:成功,报文已经收到并被正确处理;

  • 3××:重定向,资源位置发生变动,需要客户端重新发送请求;

  • 4××:客户端错误,请求报文有误,服务器无法处理;

  • 5××:服务器错误,服务器在处理请求时内部发生了错误。

接下来挑一些实际开发中比较有价值的状态码逐个介绍。

1xx

  • 101 Switching Protocols 偶尔能够见到,客户端要求在 HTTP 协议的基础上改成其他的协议继续通信,比如 WebSocket。而如果服务器也同意变更协议,就会发送状态码 101,但这之后的数据传输就不会再使用 HTTP 了。

2xx

  • 200 OK 是最常见的成功状态码,表示一切正常,服务器如客户端所期望的那样返回了处理结果,如果是非 HEAD 请求,通常在响应头后都会有 body 数据。

  • 204 No Content 是另一个很常见的成功状态码,它的含义与“200 OK”基本相同,但响应头后没有 body 数据。所以对于 Web 服务器来说,正确地区分 200 和 204 是很必要的。

  • 206 Partial Content 是 HTTP 分块下载或断点续传的基础,在客户端发送“范围请求”、要求获取资源的部分数据时出现,它与 200 一样,也是服务器成功处理了请求,但 body 里的数据不是资源的全部,而是其中的一部分。

3xx

  • 301 Moved Permanently 俗称“永久重定向”,含义是此次请求的资源已经不存在了,需要改用新的 URI 再次访问。

  • 302 Found 曾经的描述短语是“Moved Temporarily”,俗称“临时重定向”,意思是请求的资源还在,但需要暂时用另一个 URI 来访问。

    举个栗子说明两者的差别

    比如,你的网站升级到了 HTTPS,原来的 HTTP 不打算用了,这就是“永久”的,所以要配置 301 跳转,把所有的 HTTP 流量都切换到 HTTPS。
    再比如,今天夜里网站后台要系统维护,服务暂时不可用,这就属于“临时”的,可以配置成 302 跳转,把流量临时切换到一个静态通知页面,浏览器看到这个 302 就知道这只是暂时的情况,不会做缓存优化,第二天还会访问原来的地址。

  • 304 Not Modified 是一个比较有意思的状态码,它用于 If-Modified-Since 等条件请求,表示资源未修改,用于缓存控制。它不具有通常的跳转含义,但可以理解成“重定向已到缓存的文件”(即“缓存重定向”)。

4xx

  • 400 Bad Request 是一个通用的错误码,表示请求报文有错误,但也只是一个笼统的错误。

  • 403 Forbidden 实际上不是客户端的请求出错,而是表示服务器禁止访问资源,原因可能多种多样,例如信息敏感、法律禁止等。

  • 404 Not Found 可能是我们最常看见也是最不愿意看到的一个状态码,它的原意是资源在本服务器上未找到,所以无法提供给客户端。

  • 405 Method Not Allowed:不允许使用某些方法操作资源,例如不允许 POST 只能 GET;

  • 406 Not Acceptable:资源无法满足客户端请求的条件,例如请求中文但只有英文;

  • 408 Request Timeout:请求超时,服务器等待了过长的时间;

  • 409 Conflict:多个请求发生了冲突,可以理解为多线程并发时的竞态;

  • 413 Request Entity Too Large:请求报文里的 body 太大;

  • 414 Request-URI Too Long:请求行里的 URI 太大;

  • 429 Too Many Requests:客户端发送了太多的请求,通常是由于服务器的限连策略;

  • 431 Request Header Fields Too Large:请求头某个字段或总体太大;

5xx

  • 500 Internal Server Error 与 400 类似,也是一个通用的错误码,服务器究竟发生了什么错误我们是不知道的。

  • 501 Not Implemented 表示客户端请求的功能还不支持,

  • 502 Bad Gateway 通常是服务器作为网关或者代理时返回的错误码,表示服务器自身工作正常,访问后端服务器时发生了错误,但具体的错误原因也是不知道的。

  • 503 Service Unavailable 表示服务器当前很忙,暂时无法响应服务,我们上网时有时候遇到的“网络服务正忙,请稍后重试”的提示信息就是状态码 503。

1.5 HTTP 优点及缺点

优点

  1. 简单、灵活和易于扩展

    HTTP 协议是很"简单"的,基本的报文格式是"header + body",头部信息也是简单的文本格式,挺容易看懂的。

    HTTP 协议里的各个核心组成要素都没有被"写死",允许开发者任意定制、扩充和解释,如果你缺了什么功能,那你可以自己加上去。

  2. 应用广泛、环境成熟

    HTTP 目前已经遍布世界的每一个角落,不管是台式机还是移动端,不管是浏览器还是各种app,都有它的身影。

    HTTP 广泛应用的背后还有许多硬件设施的支持,各个公司纷纷购买服务器开办网站,让 HTTP 可以运行地更流畅。

  3. 无状态

    无状态是一把"双刃剑"。

    单台服务器的角度来说,无状态相当于没有"记忆能力",所以就不需要额外的资源来记录状态信息,不仅实现上会简单一些,而且还能减轻服务器的负担;

    服务器集群的角度来说,无状态也表示每台服务器都是相同的,都可以处理请求,那么就可以轻松实现负载均衡和高并发。

  4. 明文

    明文传输也是一把"双刃剑"。

    对开发者友好:对比 TCP、UDP 这样的二进制协议,开发者可以直接在浏览器上用肉眼去查看,为我们的开发调试工作带来极大的便利。

缺点

  1. 无状态

    对于服务器来说,无状态相当于没有"记忆能力",那么用户在购物的时候,从添加购物车、下单到付款,这一系列的操作,服务器都需要去跟用户验证身份才行,不仅麻烦,而且还造成很多不必要的数据传输。

  2. 明文

    信息安全问题:因为是明文,所以黑客在数据传输链路上的某个环节截取到报文的话,就可以轻松查看报文信息,毫无隐私可言。

  3. 不安全

    机密性:不能让别人知道你传输的是什么,"明文"就是这方面的一个缺点;
    完整性:黑客可以修改报文里面的信息,但 HTTP 协议无法验证是否被修改;
    身份认证:你可以发送请求,黑客也可以发送请求,那么怎么确认这个请求不是黑客发的呢?这个 HTTP 无法给出答案。

2 进阶篇

2.1 HTTP实体数据

  1. 数据类型表示实体数据的内容是什么,使用的是 MIME type,相关的头字段是 Accept 和 Content-Type;

  2. 数据编码表示实体数据的压缩方式,相关的头字段是 Accept-Encoding 和 Content-Encoding;

  3. 语言类型表示实体数据的自然语言,相关的头字段是 Accept-Language 和 Content-Language;

  4. 字符集表示实体数据的编码方式,相关的头字段是 Accept-Charset 和 Content-Type;

  5. 客户端需要在请求头里使用 Accept 等头字段与服务器进行“内容协商”,要求服务器返回最合适的数据;

  6. Accept 等头字段可以用“,”顺序列出多个可能的选项,还可以用“;q=”参数来精确指定权重。

2.2 HTTP传输大文件的方法

数据压缩

请求报文:“Accept-Encoding”,值可以是 gzip、deflate、br

相应报文:“Content-Encoding”,值是服务器选择的压缩算法

缺点:通常只对文本文件有较好的压缩率,而图片、音频视频等本身就是已经高度压缩的,此法没什么卵用

分块传输

压缩是把大文件整体变小,我们可以反过来思考,如果大文件整体不能变小,那就把它“拆开”,分解成多个小块,把这些小块分批发给浏览器,浏览器收到后再组装复原。

响应报文:“Transfer-Encoding: chunked

分块传输也可用于“流式数据”,例如由数据库动态生成的表单页面,这种情况下 body 数据的长度是未知的,无法在头字段“Content-Length”里给出确切的长度,所以也只能用 chunked 方式分块发送。

注意:“Transfer-Encoding: chunked”和“Content-Length”这两个字段是互斥的,一个是长度未知,一个是长度已知。

编码规则

HTTP笔记

采用明文方式,类似响应头

  1. 每个分块包含两个部分,长度头和数据块;

  2. 长度头是以 CRLF(回车换行,即\r\n)结尾的一行明文,用 16 进制数字表示长度;

  3. 数据块紧跟在长度头后,最后也用 CRLF 结尾,但数据不包含 CRLF;

  4. 最后用一个长度为 0 的块表示结束,即“0\r\n\r\n”。

范围请求

“范围请求”允许客户端在请求头里使用专用字段来表示只获取文件的一部分,不仅看视频的拖拽进度需要范围请求,常用的下载工具里的多段下载、断点续传也是基于它实现的。

服务器:

“Accept-Ranges: bytes”:我支持范围请求

“Accept-Ranges: none”:我不支持范围请求

没有“Accept-Ranges”字段:我不支持范围请求

“范围请求”的请求头字段:**Range,**格式为 “bytes=x-y”,其中x和y是以字节为单位的数据范围,和字符串的位置类似。

比如: “0-9”表示前10个字节,“0-”表示从文档起点到文档终点,“-1”表示文档的最后一个字节。

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

第一,它必须检查范围是否合法,比如文件只有 100 个字节,但请求“200-300”,这就是范围越界了。服务器就会返回状态码416,意思是“你的范围请求有误,我无法处理,请再检查一下”。

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

第三,服务器要添加一个响应头字段Content-Range,告诉片段的实际偏移量和资源的总大小,格式是“bytes x-y/length”,与 Range 头区别在没有“=”,范围后多了总长度。例如,对于“0-10”的范围请求,值就是“bytes 0-10/100”。

最后就是发送数据了,直接把片段用TCP发给客户端,一个范围请求就算是处理完了

多段数据

请求报文:Range头里支持使用多个"x-y",一次性获取多个片段数据

响应报文:“Content-Type: multipart/byteranges; boundary=xxx(分隔标记,示例:00000000001)”

多段数据结构如下:

HTTP笔记

2.3 HTTP的连接管理及队头阻塞

短连接

1. 理解

客户端每次发送请求前需要先与服务器建立连接,收到响应报文后会立即关闭连接。整个连接过程很短暂,所以就被称为“短连接”(short-lived connections)。

2. 缺点

每次的请求都会造成无谓的TCP连接建立和断开,导致传输效率很低。

长连接

HTTP笔记

1. 理解

针对短连接暴露出的缺点,HTTP协议提出了“长连接”的通信方式,也叫“持久连接”(persistent connections)、“连接保活”(keep alive)、“连接复用”(connection reuse)。

特点是:只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。

2. 好处

对服务器端:减少了 TCP 连接的重复建立和断开所造成的额外开销,减轻了服务器端的负载。

对客户端:减少开销的那部分时间,使 HTTP 请求和响应能够更早地结束,这样 Web 页面的显示速度也就相应提高了。

连接相关的头字段

HTTP/1.1 中的连接都会默认启用长连接。

启用长连接:

请求报文:“Connection: keep-alive”,可有可无

相应报文:“Connection: keep-alive”,支持即有

关闭长连接:

客户端:请求报文加上"Connection: close",告诉服务器:“这次通信通信后就关闭连接”

服务器:通常不会主动关闭连接,但也可以使用一些策略。拿 Nginx 来举例,有 “keepalive_timeout” 和 “keepalive_requests” 两种方式。

队头阻塞

HTTP笔记

理解

HTTP 采用了“请求 - 应答”模式进行通信,而且 HTTP 规定了报文必须是“一发一收”,这就形成了一个先进先出的“串行”队列,如果队首的请求处理太慢,后面的请求就会一直处于等待状态。这就是著名的“队头阻塞”(Head-of-line blocking,也叫“队首阻塞”)了。

并发连接

同时对一个域名发起多个长连接,就好像蓄水池里多了几条管子用于排水,如果一根管子不幸堵了,那么其他管子还可以继续排水。

RFC2616里明确限制每个客户端最多并发2个连接,不过浏览器把这个上限提高到了6~8。后来修订的 RFC7230 也就取消了这个“2”的限制。

这是用数量来解决质量的问题,只不过它所提供的性能也跟不上互联网告诉发展所带来的需求。

域名分片

既然一个域名只能并发连接6~8个,那我索性就多开几个域名,比如 shard1.chrono.com、shard2.chrono.com,而这些域名都指向同一台服务器 www.chrono.com,这样实际长连接的数量就又上去了。这就是域名分片。

2.4 HTTP的Cookie机制

什么是 Cookie

Cookie 是服务器委浏览器存储在客户端里的一些数据,而这些数据通常都会记录用户的关键识别信息。

Cookie 的作用

身份识别

Cookie 最基本的一个用途就是 身份识别,保存用户的登录信息,实现会话事务。

比如你用账号密码登录了某宝,登录成功后服务器会给浏览器发一个Cookie,内容大概是"name=yourid",这样子你再次发送请求,浏览器就会自动把 Cookie 发给服务器,服务器就知道这个人是你,而不是张三,从而实现个性化服务。一方面是不用重复登录,另一方面也能记录你的浏览记录。

广告跟踪

Cookie 是怎么使用的

首先我们需要知道 Cookie 使用的两个字段:

响应头字段:Set-Cookie

请求头字段:Cookie

然后我们看看流程:

  1. 浏览器第一次访问服务器,服务器那肯定不知道他的身份,就创建了一个独特的身份标识数据,格式呢是 “key=value”,然后放到 Set-Cookie 里面,发送给浏览器(注意可以有多个 Set-Cookie);

  2. 这么一来一回之后,浏览器就能看到相应报文里面的 Set-Cookie,*知道这是服务器给的身份标识,于是呢就保存起来,*下次发送请求的时候把这个值放到 Cookie 字段里面发给服务器。

  3. 服务器看到第二次请求里面有 Cookie,就晓得这不是新人,*就可以拿出 Cookie 里的值,识别出其身份,*然后对其进行个性化服务。

流程具体如下图:
HTTP笔记

注意 Cookie 是由浏览器负责存储的,所以如果换了浏览器或者电脑,那新的浏览器里面没有对应的 Cookie,就需要再来一遍 Set-Cookie 流程了。

最后我们来了解一下常见的 Cookie 属性,也就是 Set-Cookie 里面除了 "key=value"外的一些手段,主要用于保护用户关键信息,防止外泄或窃取。先看看下图:
HTTP笔记
按手段的作用,属性分为以下几类:

  1. 设置 Cookie 的生命周期

    (1)“Expires” 俗称 “过期时间”,用的是绝对时间,可以理解为 “截止日期”(deadline);

    (2)“Max-Age” 用的是相对时间,单位是秒。浏览器用收到报文的时间点再加上 Max-Age,就可以得到失效的绝对时间。

    这俩可以同时出现,但浏览器会优先采用 “Max-Age” 计算失效期。

  2. 设置 Cookie 的作用域

    (1)“Domain” 指定 Cookie 所属的域名;

    (2)“Path” 指定 Cookie 所属的路径。

    浏览器在发送 Cookie 前会从 URI 中提取出 host 和 path 部分,对比 Cookie 的属性。如果不满足条件,就不会在请求头里发送 Cookie。

  3. 保证 Cookie 的安全性

    (1)“HttpOnly” 会告诉浏览器,此 Cookie 只能通过浏览器 HTTP 协议传输,禁止其他方式访问,浏览器的 JS 引擎就会禁用 document.cookie 等一切相关的 API,“跨站脚本”(XSS)攻击也就无从谈起了。

    (2)“SameSite” 可以防范“跨站请求伪造”(XSRF)攻击,设置成“SameSite=Strict”可以严格限定 Cookie 不能随着跳转链接跨站发送,而“SameSite=Lax”则略宽松一点,允许 GET/HEAD 等安全方法,但禁止 POST 跨站发送。

    (3)“Secure” 表示这个 Cookie 仅能用 HTTPS 协议加密传输,明文的 HTTP 协议会禁止发送。但 Cookie 本身不是加密的,浏览器里还是以明文的形式存在。

2.5 HTTP 代理

理解

我们知道 HTTP 是基于 “请求 - 应答” 模型的协议,一般由客户端发请求,由服务器响应。

实际上,在实际情况中,会有代理的存在。它呢,就是在客户端和服务器原本的通信链路中插入的一个中间环节,也是一台服务器,但提供的是 “代理服务”。对于客户端来说,表现为服务器进行响应;对于源服务器来说,又表现为客户端发起请求,具有双重身份

HTTP笔记

作用

负载均衡

简单点理解,代理服务器收到客户端的请求后,可以决定把请求分发给众多源服务器中的哪一台。这样子一来,代理服务器可以把请求直接发给相对来说比较空闲的源服务器,这样子源服务器们就都有活干了,达到负载均衡的效果。

健康检查

使用“心跳”等机制监控后端服务器,发现有故障就及时“踢出”集群,保证服务高可用。

内容缓存

暂存、复用服务器响应。

相关头字段

Via

Via 用来标明代理的身份,是一个通用字段,在请求头或响应头里都可以出现。每当报文经过一个代理节点,代理服务器就会把自身的信息追加到字段的末尾,就像是经手人盖了一个章。如下图:

HTTP笔记

X-Forwarded-For

“X-Forwarded-For”的字面意思是“为谁而转发”,形式上和“Via”差不多,也是每经过一个代理节点就会在字段里追加一个信息。但“Via”追加的是代理主机名(或者域名),而“X-Forwarded-For”追加的是请求方的 IP 地址。所以,在字段里最左边的 IP 地址就客户端的地址。

X-Real-IP

“X-Real-IP”是另一种获取客户端真实 IP 的手段,它的作用很简单,就是记录客户端 IP 地址,没有中间的代理信息,相当于是“X-Forwarded-For”的简化版。如果客户端和源服务器之间只有一个代理,那么这两个字段的值就是相同的。

X-Forwarded-Host 和 X-Forwarded-Proto

它们的作用与“X-Real-IP”类似,只记录客户端的信息,分别是客户端请求的原始域名和原始协议名。

代理协议

对于代理服务器来说,通过 “X-Forwarded-For” 操作代理信息,一个是必须要解析 HTTP 报文头,这对于代理来说成本比较高;另一个是 “X-Forwarded-For” 等头必须要修改原始报文,而有些情况下是不允许甚至不可能的(比如使用 HTTPS 通信被加密)

所以出现了一个专门的 “代理协议”,用来拿到准确的客户端信息。以下是 “代理协议” v1 版本的示例,它在 HTTP 报文前增加了一行 ASCII 码文本,相当于多了一个头。

// PROXY TCP4/TCP6 请求方地址 应答方地址 请求方端口号 应答方端口号 \r\n
PROXY TCP4 1.1.1.1 2.2.2.2 55555 80\r\n
GET / HTTP/1.1\r\n
Host: www.xxx.com\r\n
\r\n

2.6 HTTP 的缓存控制

2.6.1 缓存

缓存是什么

Web 缓存是可以自动保存常见文档副本的 HTTP 设备。当 Web 请求抵达缓存时,如果本地有“已缓存的”副本,就可以从本地存储设备而不是原始服务器中提取这个文档(来自HTTP权威指南,不过一般我都会把缓存直接理解成数据)

缓存的优点

  • 缓存减少了冗余的数据传输,节省了你的网络费用。

  • 缓存缓解了网络瓶颈的问题。不需要更多的带宽就能够更快地加载页面。

  • 缓存降低了对原始服务器的要求。服务器可以更快地响应,避免过载的出现。

  • 缓存降低了距离时延,因为从较远的地方加载页面会更慢一些。

以上也是从《HTTP权威指南》抄的,不过我总结起来也就是:

  • 对网络来说:避免多次请求 - 应答的通信成本,节约网络带宽;

  • 对源服务器来说:减轻了对源服务器的压力;

  • 对客户端来说:网页的响应速度变得更快了。

缓存的缺点

  • 缓存中的数据可能与服务器的数据不一致;
  • 消耗内存。

2.6.2 浏览器缓存

浏览器缓存分为强缓存协商缓存,当客户端请求某个资源时,获取缓存的流程如下

首先通过 Cache-Control 头字段验证强缓存是否可用

  • 如果强缓存可用,直接使用;

  • 否则进入协商缓存,即发送 HTTP 请求,服务器通过请求头中的 If-Modified-Since 或者 If-None-Match 这些条件请求字段检查资源是否更新

    • 若资源更新,返回资源和200状态码
    • 否则,返回304状态码,告知浏览器直接从缓存获取数据

强缓存相关头字段

Cache-Control: max-age=30; no_store/no_cache/must-revalidate

Cache-Control 头字段有以下几个属性:

  • max-age:HTTP 缓存控制最常用属性,标记资源的有效期,也就是"生存时间",时间的计算起点是响应报文的创建时刻,而不是客户端收到报文的时刻;

  • no_store:不允许缓存,用于某些变化非常频繁的数据,例如秒杀页面;

  • no_cache:这是一个容易引起误会的属性,它不是不可以缓存,实际上可以缓存,只不过需要在使用缓存之前要向服务器验证是否过期;

  • must-revalidate:这个可以根据语义来理解(revalidate,使重新生效),它的意思是如果缓存不过期就可以继续使用,但过期了如果还想用就必须去服务器验证。

协商缓存相关头字段

条件请求,或者说协商缓存,一共有 5 个头字段,我们最常用的是“If-Modified-Since”和“If-None-Match”这两个。需要第一次的响应报文预先提供“Last-modified”和“ETag”,然后第二次请求时就可以带上缓存里的原值,验证资源是否是最新的。

如果资源没有变,服务器就回应一个“304 Not Modified”,表示缓存依然有效,浏览器就可以更新一下有效期,然后放心大胆地使用缓存了。

HTTP笔记

If-Modified-Since” 对应的是 “Last-modified”(文件的最后修改时间),其实根据语义就能明白大概意思

If-None-Match” (Match 是匹配的意思)对应的是 “ETag”,这什么意思呢?ETag 是“实体标签”(Entity Tag)的缩写,是资源的一个唯一标识,主要是用来解决修改时间无法准确区分文件变化的问题。

比如,一个文件在一秒内修改了多次,但因为修改时间是秒级,所以这一秒内的新版本无法区分。

再比如,一个文件定期更新,但有时会是同样的内容,实际上没有变化,用修改时间就会误以为发生了变化,传送给浏览器就会浪费带宽。

使用 ETag 就可以精确地识别资源的变动情况,让浏览器能够更有效地利用缓存。

ETag 还有“强”“弱”之分。

强 ETag 要求资源在字节级别必须完全相符,弱 ETag 在值前有个“W/”标记,只要求资源在语义上没有变化,但内部可能会有部分发生了改变(例如 HTML 里的标签顺序调整,或者多了几个空格)。

3 安全篇

3.1 HTTPS

HTTPS

简单来说,HTTPS = HTTP + SSL/TLS,也就是在 HTTP 下加入了 SSL/TLS 层,让 HTTP 运行在了安全SSL/TLS 协议上,所以在安全性上面全靠 SSL/TLS

HTTPS 的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。

SSL/TCL

SSL/TLS 是信息安全领域中的权威标准,采用多种先进的加密技术保证通信安全;

SSL 即安全套接层(Secure Sockets Layer),在 OSI 模型中处于第 5 层(会话层);SSL 发展到 v3 版本时被正式标准化,并改名为 TLS(传输层安全,Transport Layer Security),版本号从 1.0 重新算起,所以 TLS1.0 = SSLv3.1。目前应用的最广泛的 TLS 是 1.2 版本。

OpenSSL 是著名的开源密码学工具包,是 SSL/TLS 的具体实现。

HTTPS 最大的特点和缺点

HTTP 最大的特点就是安全,在机密性、完整性、身份认证方面都有保障。

HTTP的缺点:

1、证书费用以及更新维护。

2、HTTPS 降低一定用户访问速度(实际上优化好就不是缺点了)。

3、HTTPS 消耗 CPU 资源,需要增加大量机器。

HTTP 和 HTTPS 的区别

  1. https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。

  2. http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。

  3. http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

  4. http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

3.2 HTTP 如何保证安全性

  1. 对称加密和非对称加密,以及两者结合起来的混合加密,实现了机密性。 目前 TLS 使用的就是混合加密

  2. 实现完整性的手段主要是摘要算法(Digest Algorithm),也就是常说的散列函数、哈希函数(Hash Function)。

  3. 使用私钥再加上摘要算法,就能够实现“数字签名”,同时实现身份认证不可否认

补充:

CA

由于谁都可以发布公钥,所以还有“公钥的信任”问题。由此引入了**“第三方”CA**( Certificate Authority,证书认证机构 )。 它就像网络世界里的*局、教育部、公证中心,具有极高的可信度,由它来给各个公钥签名,用自身的信誉来保证公钥无法伪造,是可信的。

数字证书

​ CA 对公钥的签名认证也是有格式的,不是简单地把公钥绑定在持有者身份上就完事了,还要包含序列号、用途、颁发者、有效时间等等,把这些打成一个包再签名,完整地证明公钥关联的各种信息,形成“数字证书”(Certificate)。

4 飞翔篇

4.1 HTTP/2

由于 HTTPS 通过引入 SSL/TLS 在安全上达到了"极致",但在性能提升方面做得不多,所以 HTTP/2 主要在性能优化上做了提升,和 HTTP/1 相比,主要有以下几点区别:

  1. 头部压缩:HTTP/2 使用“HPACK”算法压缩头部信息,消除冗余数据节约带宽;
  2. 二进制格式:HTTP/2 的消息不再是“Header+Body”的形式,而是分散为多个二进制“帧”;

HTTP笔记

  1. 数据流:HTTP/2 使用了数据流的概念,因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的请求。因此,必须要对数据包做标记,指出它属于哪个请求。HTTP/2 将每个请求或回应的所有数据包,称为一个数据流。每个数据流都有一个独一无二的编号。数据包发送时,都必须标记数据流 ID ,用来区分它属于哪个数据流。
  2. 多路复用: HTTP/2 实现了多路复用,HTTP/2 仍然复用 TCP 连接,但是在一个连接里,客户端和服务器都可以同时发送多个请求或回应,而且不用按照顺序一一发送,这样就避免了"队头堵塞"的问题。
    HTTP笔记
  3. 服务器推送:服务器可以新建数据流主动向客户端发送消息。比如,在浏览器请求 HTML 的时候就提前把可能会用到的 CSS、JS 文件发送给浏览器,减少等待的时间,这就是"服务器推送"。

附:

键入网址按下回车,后面发生了什么?

简单版本:

  1. 浏览器从地址栏的输入中获得服务器的 IP 地址和端口号;

  2. 浏览器用 TCP 的三次握手与服务器建立连接;

  3. 浏览器向服务器发送拼好的请求报文;

  4. 服务器收到报文后处理请求,同样拼好响应报文再发给浏览器;

  5. 浏览器解析报文,渲染输出页面。

对URI的理解

先举个栗子

http://www.chrono.com:8080/11-1?uid=1234&name=mario&referer=xxx

HTTP笔记

  1. URI 是用来唯一标记服务器上资源的一个字符串,通常也称为 URL;

  2. URI 通常由 scheme、host:port、path 和 query 四个部分组成,有的可以省略;

  3. scheme 叫“方案名”或者“协议名”,表示资源应该使用哪种协议来访问;

  4. “host:port”表示资源所在的主机名和端口号;

  5. path 标记资源所在的位置;

  6. query 表示对资源附加的额外要求;

  7. 在 URI 里对“@&/”等特殊字符和汉字必须要做编码,否则服务器收到 HTTP 报文后会无法正确处理。

参考文献:

上一篇:web自动化


下一篇:谷歌浏览器Chrome 80版本默认SameSite导致跨域请求Cookie丢失