网络-HTTP,HTTPS详解

网络-HTTP,HTTPS详解

一: 基础概念

1.1 URI

  • URI 包含 URL 和 URN。
  • 我们通常所说的URL(统一资源定位符)是URI的子集
  • URI还有一个自己URN , URN只命名资源但是不指定如何定位资源.

mark

1.2 请求报文

mark

1.3 响应报文

mark

二: HTTP 请求方法

客户端发送的 请求报文 第一行为请求行,包含了方法字段。

举例:

mark

1.1 GET

  • 获取资源的请求(绝大部分的请求都是GET方法)

1.2 HEAD

  • 获取报文的首部,但是不返回报文实体主体部分
  • 主要用于确认URL的有效性以及资源更新的日期时间等.

1.3 POST

  • 传输实体主体
  • POST用于传输表单数据,具体和GET的区别会在下文进行阐述

1.4 PUT

  • 上传文件
  • 由于自身不带验证机制,任何人都可以上传文件,因此存在安全性问题,一般不使用这个方法.
1
2
3
4
5
6
PUT /new.html HTTP/1.1
Host: example.com
Content-type: text/html
Content-length: 16

<p>New File</p>

1.5 PATCH

  • 类似与PUT,但是PATCH用于资源的部分修改
1
2
3
4
5
6
7
PATCH /file.txt HTTP/1.1
Host: www.example.com
Content-Type: application/example
If-Match: "e0023aa4e"
Content-Length: 100

[description of changes]

1.6 DELTETE

  • 删除文件

  • 与PUT功能相反,并且同样不携带验证机制.

1.7 OPTIONS

  • 支持查询的方法
  • 作用:查询指定的URL能够支持的方法(会返回 Allow GET POST HEAD OPTIONS) 这样的内容

1.8 Connect

  • 要求在与代理服务器通信时建立隧道
  • 使用SSL(Secure Sockets Layer,安全套接层) 和 TLS (Transport Layer Security,传输层安全)协议把通信内容加密后经网络隧道传输.
1
CONNECT www.example.com:443 HTTP/1.1

mark

1.9 TRACE

  • 追踪路径
  • 服务器会将通信路径返回给客户端(在 Max-Forwards 首部字段中填入数值,每经过一个服务器就会减 1,当数值为 0 时就停止传输。)
  • 通常不会使用TRACE,并且它容易受到XST攻击(Cross-Site Tracing ,跨站追踪)

三: HTTP 状态码

  • 服务器返回的 响应报文 中第一行为状态行,包含了状态码以及原因短语,用来告知客户端请求的结果。
状态码 类别 含义
1XX Informational(信息状态码) 接收的请求正现在处理
2XX Success(成功状态码) 请求正常处理完毕
3XX Redirection(重定向状态码) 需要进行附加操作以完成请求
4XX Client Error(客户端错误状态码) 服务器无法处理请求
5XX Server Error(服务器错误状态码) 服务器处理请求发生错误

mark

1XX 信息

  • 100 Continue : 表示到目前为止数据都很正常,客户端可以继续发送请求或者忽略这个响应.

2XX 成功

  • 200 OK
  • 204 No Content: 请求已经成功处理,但是返回的响应报文不包含实体的主体部分.一般在只需要从客户端向服务器发送信息,而不需要返回数据的时候使用.
  • 206 Partial Content: 表示客户端进行的范围请求,响应报文包含由Content-Range 指定范围的实体内容.

3XX 重定向

  • 301 Moved Permanently : 永久性重定向

  • 302 Found: 临时性重定向

  • 303 See Other : 和302 有着相同的功能,但是303明确要求客户端应该采用GET方法请求资源

    • 注:虽然 HTTP 协议规定 301、302 状态下重定向时不允许把 POST 方法改成 GET 方法,但是大多数浏览器都会在 301、302 和 303 状态下的重定向把 POST 方法改成 GET 方法。
  • 304 Not Modified : 如果请求报文首部包含一些条件,例如:If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,如果不满足以上条件,则服务器会返回304状态码.

  • 307 Temporary Redirect : 临时重定向,与302的含义类似,但是307要求浏览器不会把重定向请求的POST方法修改成GET 方法.

4XX 客户端错误

  • 400 Bad Request :: 请求报文中存在语法错误
  • 401 Unauthorizd : 该状态码表示发送的请求去需要有认证信息(BASIC 认证、DIGEST 认证)。如果之前已进行过一次请求,则表示用户认证失败。
  • 403 Forbidden : 请求被拒绝
  • 404 Not found

5XX 服务器错误

  • 500 Internal Server Error :服务器正在执行请求时发生错误。
  • 503 Service Unavailable: 服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。

四 : HTTP 首部

  • 有四种类型的首部字段
    • 通用首部字段
    • 请求首部字段
    • 响应首部字段
    • 实体首部字段

4.1 通用首部字段

首部字段名 说明
Cache-Control 控制缓存的行为
Connection 控制不再转发给代理的首部字段、管理持久连接
Date 创建报文的日期时间
Pragma 报文指令
Trailer 报文末端的首部一览
Transfer-Encoding 指定报文主体的传输编码方式
Upgrade 升级为其他协议
Via 代理服务器的相关信息
Warning 错误通知

4.2 请求首部字段

首部字段名 说明
Accept 用户代理可处理的媒体类型
Accept-Charset 优先的字符集
Accept-Encoding 优先的内容编码
Accept-Language 优先的语言(自然语言)
Authorization Web 认证信息
Expect 期待服务器的特定行为
From 用户的电子邮箱地址
Host 请求资源所在服务器
If-Match 比较实体标记(ETag)
If-Modified-Since 比较资源的更新时间
If-None-Match 比较实体标记(与 If-Match 相反)
If-Range 资源未更新时发送实体 Byte 的范围请求
If-Unmodified-Since 比较资源的更新时间(与 If-Modified-Since 相反)
Max-Forwards 最大传输逐跳数
Proxy-Authorization 代理服务器要求客户端的认证信息
Range 实体的字节范围请求
Referer 对请求中 URI 的原始获取方
TE 传输编码的优先级
User-Agent HTTP 客户端程序的信息

4.3 响应首部字段

首部字段名 说明
Accept-Ranges 是否接受字节范围请求
Age 推算资源创建经过时间
ETag 资源的匹配信息
Location 令客户端重定向至指定 URI
Proxy-Authenticate 代理服务器对客户端的认证信息
Retry-After 对再次发起请求的时机要求
Server HTTP 服务器的安装信息
Vary 代理服务器缓存的管理信息
WWW-Authenticate 服务器对客户端的认证信息

4.4 实体首部字段

首部字段名 说明
Allow 资源可支持的 HTTP 方法
Content-Encoding 实体主体适用的编码方式
Content-Language 实体主体的自然语言
Content-Length 实体主体的大小
Content-Location 替代对应资源的 URI
Content-MD5 实体主体的报文摘要
Content-Range 实体主体的位置范围
Content-Type 实体主体的媒体类型
Expires 实体主体过期的日期时间
Last-Modified 资源的最后修改日期时间

五:具体应用

5.1 连接管理

5.1.1 短链接和长连接


  • 当浏览器访问一个包含多张图片的html 的时候,除了请求访问的HTML资源,还会请求图片的资源。如果每进行一次HTTP通信就要新建一个TCP连接,那么开销会很大。
    • 长连接只需要建立一次TCP链接就能就行多次HTTP通信。
      • 从 HTTP/1.1 开始默认是长连接的,如果要断开连接,需要由客户端或者服务器端提出断开,使用 Connection : close
      • 在 HTTP/1.1 之前默认是短连接的,如果需要使用长连接,则使用 Connection : Keep-Alive

5.1.2 流水线

  • 默认情况下,HTTP请求时按顺序发出的,下一个请求只有在当前请求收到响应后才会被发出

  • 由于受到网络延迟和带宽的限制,在下一个请求被发送到服务器之前,可能需要等待很长时间。

  • 流水线时在同一条长连接上连续发出请求,而不用等待响应返回,这样可以减少延迟。

  • HTTP 协议是无状态的,主要是为了让 HTTP 协议尽可能简单,使得它能够处理大量事务。HTTP/1.1 引入 Cookie 来保存状态信息。

  • Cookie 是服务器发送到用户浏览器并在本地保存的一小块数据,他会在浏览器之后向同一服务器再次发起请求时被携带上,用于告知服务端两个请求是否来自同一浏览器。

  • 于之后每次请求都会需要携带 Cookie 数据,因此会带来额外的性能开销(尤其是在移动环境下)。

  • Cookie 曾一度用于客户端数据的存储,因为当时并没有其它合适的存储办法而作为唯一的存储手段,但现在随着现代浏览器开始支持各种各样的存储方式,Cookie 渐渐被淘汰。

    • 新的浏览器API 已经允许开发者直接将数据存储到本地,如使用Web Storage API(本地存储和会话存储)或者 IndexedDB.
  1. Cookie的用途
  • 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
  • 个性化设置(如用户自定义设置、主题等)
  • 浏览器行为跟踪(如跟踪分析用户行为等)
  1. 创建过程
  • 服务器发送的响应报文包含 Set-Cookie 首部字段,客户端得到响应报文后把 Cookie 内容保存到浏览器中。
1
2
3
4
5
6
HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry

[page content]
  • 客户端之后对同一个服务器发起请求的时候,会从浏览器中取出Cookie 信息并通过Cookie 请求首部字段发送给服务器。
1
2
3
GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry
  1. 分类
  • 会话期 Cookie浏览器关闭之后它会被自动删除,也就是说它仅在会话期内有效。
  • 持久性 Cookie指定过期时间(Expires)或有效期(max-age)之后就成为了持久性的 Cookie。
1
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;
  1. 作用域
  • Domain 标识指定了哪些主机可以接受 Cookie。

    • 如果不指定,默认为当前文档的主机(不包含子域名)。
    • 如果指定了 Domain,则一般包含子域名。例如,如果设置 Domain=mozilla.org,则 Cookie 也包含在子域名中(如 developer.mozilla.org)。
  • Path 标识指定了主机下的哪些路径可以接受 Cookie(该 URL 路径必须存在于请求 URL 中)。以字符 %x2F (“/“) 作为路径分隔符,子路径也会被匹配。例如,设置 Path=/docs,则以下地址都会匹配:

    • /docs
    • /docs/Web/
    • /docs/Web/HTTP
  1. javaScript
  • 浏览器通过 document.cookie 属性可创建新的 Cookie,也可通过该属性访问非 HttpOnly 标记的 Cookie。
1
2
3
document.cookie = "yummy_cookie=choco";
document.cookie = "tasty_cookie=strawberry";
console.log(document.cookie);
  1. HttpOnly
  • 标志为httpOnly 的 Cookie 不能被 javaScript 脚本调用,跨站脚本(XSS)常常使用JavaScript 的 document.cookie API来窃取用户的 Cookie 信息,因此 HTTPONLY 标志可以一定程序上避免XSS攻击。
1
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly
  1. Secure
  • 标记为 Secure 的 Cookie 只能通过被 HTTPS 协议加密过的请求发送给服务端。
  • 但即便设置了 Secure 标记,敏感信息也不应该通过 Cookie 传输,因为 Cookie 有其固有的不安全性,Secure 标记也无法提供确实的安全保障。
  1. Session
  • 除了可以将用户信息通过 Cookie 存储在用户浏览器中,也可以利用 Session 存储在服务器端,存储在服务器端的信息更加安全。

  • Session 可以存储在服务器上的文件、数据库或者内存中。也可以将 Session 存储在 Redis 这种内存型数据库中,效率会更高。

使用Session维护用户登录状态过程如下:

  • 用户进行登录的时候,用户提交包含用户名和密码的表单,放入HTTP请求报文中。
  • 服务器验证用户名和密码,如果正确就把用户信息存储到Redis中,他在Redis中的key 叫做Session ID;
  • 服务器返回响应报文的Set - Cookie 首部字段包含了 Session ID , 客户端收到响应报文之后将Cookie 值存入浏览器中。
  • 客户端之后对同一个服务器进行请求时会包含该 Cookie 值,服务器收到之后提取出 Session ID,从 Redis 中取出用户信息,继续之前的业务操作。

应该注意 Session ID 的安全性问题,不能让它被恶意攻击者轻易获取,那么就不能产生一个容易被猜到的 Session ID 值。此外,还需要经常重新生成 Session ID。在对安全性要求极高的场景下,例如转账等操作,除了使用 Session 管理用户状态之外,还需要对用户进行重新验证,比如重新输入密码,或者使用短信验证码等方式。

  1. 禁用Cookie
  • 此时无法使用 Cookie 来保存用户信息,只能使用 Session。除此之外,不能再将 Session ID 存放到 Cookie 中,而是使用 URL 重写技术,将 Session ID 作为 URL 的参数进行传递。
  1. Cookie 和 Session 的选择
  • Cookie 只能存储 ASCII 码字符串,而 Session 可以存储任何类型的数据,因此考虑数据复杂性首选Session.
  • Cookie 存在浏览器中,容易被恶意查看。如果非要将一些隐私数据存在 Cookie 中,可以将 Cookie 值进行加密,然后在服务器进行解密;
  • 对于大型网站,如果所有用户信息都存储在Session中,那么开销是十分大的,因此不建议将所有信息都存储在Session中。

5.3 缓存

优点:

  • 缓解服务器压力;
  • 降低客户端获取资源的延迟:缓存通常位于内存中,读取缓存的速度更快。并且缓存服务器在地理位置上也有可能比源服务器来得近,例如浏览器缓存。

5.3.1 实现方式

  • 让代理服务器进行缓存
  • 让客户端进行缓存

5.3.2 Cache-Control

  • HTTP/1.1 通过 Cache-Control 首部字段来控制缓存。

禁止使用缓存

  • no-store 指令规定不能对请求或响应的任何一部分进行缓存。
1
Cache-Control: no-store

强制确认缓存

  • no-cache 指令规定缓存服务器需要先向源服务器验证缓存资源的有效性,只有当缓存资源有效时才能使用该缓存对客户端的请求进行响应。
1
Cache-Control: no-cache

私有缓存和公共缓存

  • private 指令规定了将资源作为私有缓存,只能被单独用户使用,一般存储在用户浏览器中。
1
Cache-Control: private
  • public 指令规定了将资源作为公共缓存,可以被多个用户使用,一般存储在代理服务器中。
1
Cache-Control: public

5.3.3 缓存过期机制

  • max-age 指令出现在请求报文,并且缓存资源的缓存时间小于该指令指定的时间,那么就能接受该缓存。

    max-age 指令出现在响应报文,表示缓存资源在缓存服务器中保存的时间。

1
Cache-Control: max-age=31536000
  • Expires 首部字段也可以用于告知缓存服务器该资源什么时候会过期。
1
Expires: Wed, 04 Jul 2012 08:26:05 GMT
  • 在 HTTP/1.1 中,会优先处理 max-age 指令;
  • 在 HTTP/1.0 中,max-age 指令会被忽略掉。

5.3.4 缓存验证

需要先了解 ETag 首部字段的含义,它是资源的唯一标识。URL 不能唯一表示资源,例如 http://www.google.com/ 有中文和英文两个资源,只有 ETag 才能对这两个资源进行唯一标识。

1
ETag: "82e22293907ce725faf67773957acd12"

可以将缓存资源的 ETag 值放入 If-None-Match 首部,服务器收到该请求后,判断缓存资源的 ETag 值和资源的最新 ETag 值是否一致,如果一致则表示缓存资源有效,返回 304 Not Modified。

1
If-None-Match: "82e22293907ce725faf67773957acd12"

Last-Modified 首部字段也可以用于缓存验证,它包含在源服务器发送的响应报文中,指示源服务器对资源的最后修改时间。但是它是一种弱校验器,因为只能精确到一秒,所以它通常作为 ETag 的备用方案。如果响应首部字段里含有这个信息,客户端可以在后续的请求中带上 If-Modified-Since 来验证缓存。服务器只在所请求的资源在给定的日期时间之后对内容进行过修改的情况下才会将资源返回,状态码为 200 OK。如果请求的资源从那时起未经修改,那么返回一个不带有实体主体的 304 Not Modified 响应报文。

1
Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT
1
If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT

5.4 内容协商

  • 通过内容协商返回最合适的内容,例如根据浏览器的默认语言选择返回中文界面还是英文界面。
  1. 类型

1.1 服务端驱动型

客户端设置特定的 HTTP 首部字段,例如 Accept、Accept-Charset、Accept-Encoding、Accept-Language,服务器根据这些字段返回特定的资源。

它存在以下问题:

  • 服务器很难知道客户端浏览器的全部信息;
  • 客户端提供的信息相当冗长(HTTP/2 协议的首部压缩机制缓解了这个问题),并且存在隐私风险(HTTP 指纹识别技术);
  • 给定的资源需要返回不同的展现形式,共享缓存的效率会降低,而服务器端的实现会越来越复杂。

1.2 代理驱动型

服务器返回 300 Multiple Choices 或者 406 Not Acceptable,客户端从中选出最合适的那个资源。

  1. Vary
  • 在使用内容协商的情况下,只有当缓存服务器中的缓存满足内容协商条件时,才能使用该缓存,否则应该向源服务器请求该资源。
  • 例如,一个客户端发送了一个包含 Accept-Language 首部字段的请求之后,源服务器返回的响应包含 Vary: Accept-Language 内容,缓存服务器对这个响应进行缓存之后,在客户端下一次访问同一个 URL 资源,并且 Accept-Language 与缓存中的对应的值相同时才会返回该缓存。

5.6 内容编码

  • 内容编码将实体主体进行压缩,从而减少传输的数据量。
  • 常用的内容编码有:gzip、compress、deflate、identity。
  • 浏览器发送 Accept-Encoding 首部,其中包含有它所支持的压缩算法,以及各自的优先级。服务器则从中选择一种,使用该算法对响应的消息主体进行压缩,并且发送 Content-Encoding 首部来告知浏览器它选择了哪一种算法。由于该内容协商过程是基于编码类型来选择资源的展现形式的,响应报文的 Vary 首部字段至少要包含 Content-Encoding。

5.7 范围请求

  • 如果网络出现中断,服务器只发送了一部分数据,范围请求可以使得客户端只请求服务器未发送的那部分数据,从而避免服务器重新发送所有数据。
  1. Range
  • 在请求报文中添加 Range 首部字段指定请求的范围。
1
2
3
GET /z4d4kWk.jpg HTTP/1.1
Host: i.imgur.com
Range: bytes=0-1023
  • 请求成功的话服务器返回的响应包含 206 Partial Content 状态码。
1
2
3
4
5
HTTP/1.1 206 Partial Content
Content-Range: bytes 0-1023/146515
Content-Length: 1024
...
(binary content)
  1. Accpet- Ranges
  • 响应首部字段 Accept-Ranges 用于告知客户端是否能处理范围请求,可以处理使用 bytes,否则使用 none。
1
Accept-Ranges: bytes
  1. 响应状态码
  • 在请求成功的情况下,服务器会返回 206 Partial Content 状态码。
  • 在请求的范围越界的情况下,服务器会返回 416 Requested Range Not Satisfiable 状态码。
  • 在不支持范围请求的情况下,服务器会返回 200 OK 状态码。

5.8 分块传输编码

  • Chunked Transfer Encoding,可以把数据分割成多块,让浏览器逐步显示页面。

5.9 多部份对象集合

一份报文主体内可含有多种类型的实体同时发送,每个部分之间用 boundary 字段定义的分隔符进行分隔,每个部分都可以有首部字段。

例如,上传多个表单时可以使用如下方式:

1
2
3
4
5
6
7
8
9
10
11
12
Content-Type: multipart/form-data; boundary=AaB03x

--AaB03x
Content-Disposition: form-data; name="submit-name"

Larry
--AaB03x
Content-Disposition: form-data; name="files"; filename="file1.txt"
Content-Type: text/plain

... contents of file1.txt ...
--AaB03x--

5.10 虚拟主机

HTTP/1.1 使用虚拟主机技术,使得一台服务器拥有多个域名,并且在逻辑上可以看成多个服务器。

5.11 通信数据转发

5.11.1 代理

  • 代理服务器接受客户端的请求,并转发给其他服务器(Nginx)

  • 使用代理的主要目的是:

    • 缓存
    • 负载均衡
    • 网络访问控制
    • 访问日志记录
  • 代理服务器分为正向代理反向代理两种

    • 用户察觉得到正向代理的存在。

    - 反向代理一般位于内部网络中,用户察觉不到

5.11.2 网关

  • 与代理服务器不同的是,网关服务器会将HTTP转换成其他协议进行通信,从而实现其他非HTTP请求 (RPC)

5.11.3 隧道

  • 使用 SSL 等加密手段,在客户端和服务器之间建立一条安全的通信线路。

六. HTTPS

HTTP 有以下安全性问题:

  • 使用明文进行通信,内容可能会被窃听;
  • 不验证通信方的身份,通信方的身份有可能遭遇伪装;
  • 无法证明报文的完整性,报文有可能遭篡改。

HTTPS 并不是新的协议,而是让HTTP 先和 SSL(Secure Sockets Layer )通信,再由SSL和TCP通信,也就是说HTTPS使用了隧道进行通信。

通过SSL ,HTTPS具有了加密(防窃听),认证(防伪装)和 完整性保护(防篡改)


6.1 加密

6.1.1 对称密钥加密

  • 对称密钥加密(Symmetric-Key Encryption),加密和解密使用的是同一个密钥。
    • 优点:运算速度快。
    • 缺点:无法安全的将密钥传输给通信方。

6.1.2 非对称加密

  • 非对称加密,又叫做公开密钥加密(Public-Key Encryption),加密和解密使用不同的密钥
  • 公开密钥所有人都可以获得,通信发送发获得接收方的公开密钥之后,就可以使用公开密钥进行加密,接收方收到通信内容后使用私有密钥进行解密。
  • 非对称密钥除了用来加密,还可以用来进行签名。因为私有密钥无法被其他人获取,因此通信发送方使用其私有密钥进行签名,通信接收方无法使用发送方的公开密钥对签名进行解密,就能判断这个签名是否正确。
  • 优点:可以更安全地将公开密钥传输给通信发送方;
  • 缺点:运算速度慢。

6.2 HTTPS采用的加密方式

  • 上面提到对称密钥加密方式的传输效率更高,但是无法安全地将密钥 Secret Key 传输给通信方
  • 而非对称密钥加密方式可以保证传输的安全性,因此我们可以利用非对称密钥加密方式将 Secret Key 传输给通信方。

HTTPS采用了混合加密的方式,正式利用了上面提到的方案::

  • 使用非对称加密的方式,传输对称密钥加密所需要的 Secret Key ,从而保证安全性
  • 获取到Secret Key 之后,在使用对称密钥方法进行通信,从而保证效率

(下图中的 Session Key 就是 Secret Key


6.3 认证

  • 通过使用 证书 来对通信放进行认证

  • 数字证书认证机构(CA,Certificate Authority)是客户端和服务器双方都信赖的第三方机构

  • 服务器的运营人员向CA提出公开密钥的申请,CA再判明提出申请的身份之后,会对已申请的公开密钥做数字签名,然后分配这个已签名的公开密钥,并将公开密钥证书后绑定在一起。

  • 进行HTTPS通信的时候,服务器会把证书发送给客户端。客户端取得其公开密钥之后,先使用数字签名进行验证,如果通过,才能开始通信。


6.4 完整性保护

  • SSL 提供报文摘要功能来对完整性进行保护。
  • HTTP 也提供了 MD5 报文摘要功能,但不是安全的。例如报文内容被篡改之后,同时重新计算 MD5 的值,通信接收方是无法意识到发生了篡改。
  • HTTPS 的报文摘要功能之所以安全,是因为它结合了加密和认证这两个操作。试想一下,加密之后的报文,遭到篡改之后,也很难重新计算报文摘要,因为无法轻易获取明文。

HTTPS的缺点:

  • 因为需要进行加密解密等过程,因此速度会更慢;
  • 需要支付证书授权的高额费用。

七 : HTTP/2.0

参考博客 : https://www.zhihu.com/question/34074946

HTTP/1.x 实现简单是以牺牲性能为代价的:

  • 客户端需要使用多个连接才能实现并发和缩短延迟;
  • 不会压缩请求和响应首部,从而导致不必要的网络流量;
  • 不支持有效的资源优先级,致使底层 TCP 连接的利用率低下。

1.0 短连接:请求完了即关闭

1.1 长连接:设置了keep- alive time 来保证TCP连接不关闭

2.0 多路复用多路复用允许同时通过单一的 HTTP/2 连接发起多重的请求-响应消息。

  • 目的就是变相的解决浏览器针对同一域名的请求限制阻塞问题。

7.1 二进制分帧层

  • HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧,它们都是二进制格式的。

在通信过程中,只会有一个 TCP 连接存在,它承载了任意数量的双向数据流(Stream)。

  • 一个数据流(Stream)都有一个唯一标识符和可选的优先级信息,用于承载双向信息。
  • 消息(Message)是与逻辑请求或响应对应的完整的一系列帧。
  • 帧(Frame)是最小的通信单位,来自不同数据流的帧可以交错发送,然后再根据每个帧头的数据流标识符重新组装。

7.2 服务端推送

  • HTTP 2.0 在客户端请求一个资源的时候,会把相关的资源一起发送给客户端,这样客户端就不用再次发起请求。
  • 例如客户端请求 page.html 页面,服务端就把script.jsstyle.css等与之相关的资源一起发给客户端。

7.3 首部压缩

HTTP/1.1 的首部带有大量信息,而且每次都要重复发送。

HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之前见过的首部字段表,从而避免了重复传输。

不仅如此,HTTP/2.0 也使用 Huffman 编码对首部字段进行压缩。


八: HTTP/1.1新特性

  • 默认是长连接
  • 支持流水线
  • 同时可以打开多个TCP连接
  • 支持虚拟主机
  • 新增状态码100
  • 支持分块传输编码
  • 新增缓存处理指令 max - age

九: GET 和 POST 比较

  1. 作用上的比较
  • get用于请求获取资源
  • POST传递传递要给表单,这个表单可以是数据的主体
  1. 参数
  • GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,
  • POST 的参数存储在实体主体中。不能因为 POST 参数存储在实体主体中就认为它的安全性更高,因为照样可以通过一些抓包工具(Fiddler)查看
  1. 字符集
  • 因为 URL 只支持 ASCII 码,因此 GET 的参数中如果存在中文等字符就需要先进行编码
  • POST支持 UTF-8
1
2
3
4
5
GET /test/demo_form.asp?name1=value1&name2=value2 HTTP/1.1

POST /test/demo_form.asp HTTP/1.1
Host: w3schools.com
name1=value1&name2=value2
  1. 安全
  • 安全的 HTTP 方法不会改变服务器状态,也就是说它只是可读的。
  • POST 却不是,因为 POST 的目的是传送实体主体内容,这个内容可能是用户上传的表单数据,上传成功之后,服务器可能把这个数据存储到数据库中,因此状态也就发生了改变。

安全的方法除了 GET 之外还有:HEAD、OPTIONS。

不安全的方法除了 POST 之外还有 PUT、DELETE。

  1. 幂等性
  • 幂等的HTTP请求,同样的请求被执行一次或者执行多次的效果是一样的,因此服务器的状态也是一样的。换句话说就是,幂等方法不应该具有副作用(统计用途除外)。
  • 所有的安全方法也都是幂等的。
  • 所以说:GET,HEAD,PUT 和 DELETE 等方法都是幂等的,而 POST 方法不是。
    • GET /pageX HTTP/1.1 是幂等的,连续调用多次,客户端接收到的结果都是一样的:
    • POST /add_row HTTP/1.1 不是幂等的,如果调用多次,就会增加多行记录:
    • DELETE /idX/delete HTTP/1.1 是幂等的,即使不同的请求接收到的状态码不一样:
  1. 可缓存

如果要对响应进行缓存,需要满足以下条件:

  • 请求报文的 HTTP 方法本身是可缓存的,包括 GET 和 HEAD,但是 PUT 和 DELETE 不可缓存,POST 在多数情况下不可缓存的。
  • 响应报文的状态码是可缓存的,包括:200, 203, 204, 206, 300, 301, 404, 405, 410, 414, and 501。
  • 响应报文的 Cache-Control 首部字段没有指定不进行缓存。
  1. XMLHttpRequest
  • 为了阐述POST和 GET的另一个区别,需要先了解一个类 XMLHttpRequest(ajax)-
  • XMLHttpRequest 是一个 API,它为客户端提供了在客户端和服务器之间传输数据的功能。它提供了一个通过 URL 来获取数据的简单方式,并且不会使整个页面刷新。这使得网页只更新一部分页面而不会打扰到用户。XMLHttpRequest 在 AJAX 中被大量使用。

在使用XMLHttpRequest 的POST方法的时候 , 浏览器会先发送Header 再发送 Data。

而Get方法会把Header和 Data一起发送。

十: HTTP无状态无链接

正文:http协议无状态中的【状态】到底指的是什么?!

先来看这句话的另外两个概念:(标准的http协议是无状态的,无连接的)

  1. 标准的http协议指的是不包括cookies, session,application的http协议,他们都不属于标准协议,虽然各种网络应用提供商,实现语言、web容器等,都默认支持它
  2. 无连接指的是什么
    1. 每一个访问都是无连接,服务器挨个处理访问队列里的访问,处理完一个就关闭连接,这事儿就完了,然后处理下一个新的
    2. 无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接

对于【无状态】,我看到很多隔着一层磨砂玻璃一样的模糊说法(官方或者教程里的说法),看着非常难受(但其实算是对的)(后来我发现我为什么觉得它看着难受了,因为他们引入了很多新的,而且明显是一个可能用在很多地方的广义名词,这些词最大的作用就是,混淆概念,下面我标注了)

  1. 协议对于事务处理没有记忆能力【事物处理】【记忆能力】
  2. 对同一个url请求没有上下文关系【上下文关系】
  3. 每次的请求都是独立的,它的执行情况和结果与前面的请求和之后的请求是无直接关系的,它不会受前面的请求应答情况直接影响,也不会直接影响后面的请求应答情况【无直接联系】【受直接影响】
  4. 服务器中没有保存客户端的状态,客户端必须每次带上自己的状态去请求服务器【状态】

这几点给了我下一步思考的方向:

  1. 【服务器中没有保存客户端的状态,客户端必须每次带上自己的状态去请求服务器 】这里的客户端的状态是不是确切地指服务器没有保存客户的信息呢?但显然不是啊
  2. 【HTTP无状态的特性严重阻碍了这些应用程序的实现,毕竟交互是需要承前启后的,简单的购物车程序也要知道用户到底在之前选择了什么商品】我对此质疑为什么无状态就不能实现购物车呢?服务器就不能存储东西了么?
  3. 【 每次的请求都是独立的,<它的执行情况和结果>与<前面的请求>和<之后的请求>是无直接关系的】我觉得这个说法比较靠谱,但是所谓的不同请求间的没有关系,是指的请求内容没有关系,还是只是指请求本身没有关系?
    1. 请求内容没有关系只可能是服务器上不存有用户数据才可能啊,但是显然是存有的啊
    2. 请求本身没有关系,这又有什么意义呢,每一次的请求有什么价值?

根据这个方向我做了一个模拟访问实验:假如没有cookie没有session,只有http的时候,那当一个注册用户访问这个购物网站的时候,会发生这些事情:

  1. 前提情况:
    1. 服务器肯定为每个注册用户建立了数据表,记录用户的数据
    2. http是无连接的
  2. 第一步需要登录
    1. 用户通过http把用户的用户名和密码发送给服务器,服务器把他们跟自己存有的用户资料对比,如果一致,则返回信息登录成功
  3. 然后用户点击某一商品页
    1. 这个动作相当于输入一个商品页的网址
    2. 假如商品页比较机密不对外公开,需要是用户才能访问
    3. 而虽然http能传送用户名和密码,而且刚才也输入了,还验证成功了,但是因为服务器既不会记得你登录的状态,你的客户端也不会存储你刚才输入的用户名和密码
    4. 所以因为这一次访问因为无法确定你的身份,只能访问失败
      1. 这时候如果要解决这个问题,而且没有cookie没有session,那就只能你在访问网址的同时继续带上你的用户名和密码(继续输入咯)其实就像我现在的APP一样
  4. 假设上一步的问题解决了,就是每次访问的时候都会手动输入用户名和密码,然后现在的情况是:你已经选了几件商品在你的购物车中,你想再添加一件商品,于是你点击某个商品旁边的加号
    1. 这个动作也相当于输入一个网址,网址的内容是发送一个请求,往你的购物车中加入这个商品
    2. 系统首先用你传来的用户名和密码验证你的身份,然后访问你的数据库,在其中的购物车属性下加一条数据,就是这个商品的数据
    3. 操作结束后,返回操作成功,并结束访问
  5. OK,实验结束,看似没有cookie没有session也能凑合解决问题,其实两个操作都有很大的问题
    1. 你每访问一次需要权限的内容都需要在客户端输入用户名和密码,这一项的繁琐就不必赘述了
    2. 你的每一次操作都要与系统底层的数据库进行交互
      1. 多次少量的访问存在非常大的性能浪费。非常容易就能想到肯定是一次大量的操作更加有效率,于是就想到了缓存区
    3. 你的非重要琐碎数据也被写进数据库中,跟你的主要数据放在一起
      1. 一次次添加和删除购物车其实只是跟你这次浏览,或者叫这次会话有关,是临时的数据,跟用户的主要信息无关,它们没什么价值,纯粹的冗余数据(不排除现在有的公司觉得这种数据也有非常大的价值可以让它们巧妙的利用),用什么存放这些临时的数据,我们也很容易想到缓存区

经过这个模拟访问实验,结合前面的思考方向,我们知道了三点:

  1. 服务器上肯定存有用户的数据,你提交的增删改查它也能够处理,所以这句话中【服务器中没有保存客户端的状态】的状态并不是指用户的数据,我们的猜测不对
  2. 我们的质疑对了,无状态能实现购物车,可以通过服务器上存有的用户数据来实现
  3. 但是,使用上面这种方式实现购物车,存在三个比较大的问题。由此,我们不禁会想,这三个问题的解决是不是跟我们不确切了解的【状态】一词有关?于是,接下来我们来通过解决这三个问题来把【状态】的意义探寻下去

由上所述,我们可以在http的基础上增加一些机制来解决上面出现的三个问题

  1. 在用户端增加一个记录本是非常有必要的,正好官方加入的cookie机制跟这个一样,它的用处也确实是上面讨论的那样,一般就是用来标识访问者的身份
  2. 在服务器增加一个缓存区能同时解决后两个问题
    1. 有了这个缓存区作为一个数据缓冲,就不用一次次地访问数据库,浪费大量计算机资源,而是在最后统一归入数据库
    2. 有了这个缓存区,你就不用把临时的数据放到数据库中了,只需要在你们交流告一段落之后,再把数据整理,把有用的数据归入数据库
  3. 这里就自然引申出了一个重要的概念:会话,它作为一个缓冲存储区被从数据库中分离出来,理由并不生硬,它有其独特的重要且不可替代的作用。这个东西恰好跟官方加入的session机制一样
    1. 另外说一个非常具有迷惑性的容易让人对session的主要作用产生偏离的理解:认为session存在的价值就是给访问者分配一个sessionID代替用户名和密码,
    2. 为什么非常具有迷惑性,因为session确实做了这件事,而且也起到了很大的作用,所以它是对的,但是只对一半,而且没有涉及问题的本质,这种情况是最危险的(看似很有说服力,把你说服了,所以你很难有动力继续找下去,但是真实情况跟它有偏差,但是偏差不大,所以又很难把你说服回来,只有隐隐的不对劲,这个时候你离真实最近,也离真实最远)
    3. 那就顺便说说它为什么是对的,也就是用session做的另一件有用的事:
      1. 给每个session一个ID,一方面用来方便自己查询,另一方面把这个ID给用户,用户下一次访问的时候就可以不用用户名和密码,而是直接使用这个ID来表明自己的身份
      2. 首先,这个ID安全吗?这个ID比直接传用户名和密码安全吗?
        1. 你很容易会想到,本来用户名和密码的组合还特地设置地比较复杂,你这换一组数字就代替了,是不是太不安全了?
        2. 我们知道http协议本身是完全不加密的,如果使用用户名和密码,第一次访问是放在http头中,后边自动保存了密码就会放在cookie中,这些都完全没有加密,它的安全性基本为0,就是裸奔了,只要被窃取,那就丢失了
        3. 所以,就这个意义来讲,sessionID的安全性跟使用用户名和密码没什么区别
        4. 但是其实,虽然http本身不能加密,但是有些软件什么的,能在应用层面手动给你加密,比如QQ就会使用户名密码加临时验证码联合哈希,sessionID加一个时间戳简单加密也是非常常用的方法
        5. 而且因为sessionID本身有有效期,即使丢了,也可能很快失效,造成的损失可能没那么大,而用户名跟密码丢了,那就大了
        6. 所以总结就是:
          1. 不严格加密的sessionID和用户名和密码一样,都不太安全
          2. 但是相比较来说,sessionID要安全一些
          3. 而使用https是完全安全的
      3. 然后,使用sessionID有哪些好处
        1. 方便直接根据ID查询用户对应的session
        2. 加密的时候计算量小
        3. 安全性不会降低,甚至还更高一些

OK,通过独立地解决纯http机制会产生的问题,我们探讨了cookie和session机制的本质。而且想到:【使用http协议,服务器中不会保存客户端的状态】所产生的问题通过增加cookie和session机制解决了,是不是就意味着这个【状态】跟cookie和session的关系非常紧密?所以这个无状态指的是【没有对 本次会话 设置一个缓存区,记录这次会话的状态,缓存区包括服务器端和用户端】但好像还是没有点破关键(主要是觉得跟前面那些官方对状态的说法不太吻合,甚至没有对应关系)

忽然我想到一个问题:一个有状态的http是什么样的?

  1. 很难直接想象有状态的http是什么样,因为http这种机制是天然无状态的

  2. 那就类比一下吧,另一个天然有状态的机制叫TCP

    1. 如果有状态的意思是它的每次请求是有联系的,那么有状态的TCP的样子是:假如一份数据分了三份TCP包发送,那这个包上面会标明这是第几个包,会标明这个包跟那几个包是有联系的,有什么联系
  3. 但好像这个有状态的TCP跟我们想要的有状态的HTTP没有关系,因为即使每次http请求之间互相有联系,它也不能解决上面提到的http无状态的问题

  4. 诶,等等,好像能类比:

    1. 假如每个http连接都有一个签名,于是第一次登陆成功之后,服务器就知道了这个签名是允许登陆的,于是之后所有同样签名的http连接都能登陆,这里利用了同一个用户发出的http连接之间的同主人关系,这里解决了一个保持登录状态的问题

    2. 同样,来尝试利用这个【每次http请求之间互相有联系】来解决上面碰到的那个问题【每一次操作都要与系统底层的数据库进行交互】,但想了半天确实无法进行下去

    3. 不过我灵机一动,从另一个角度来想,好像解决了这个问题:

      1. 只有【每次http请求之间互相有联系】这个条件,无法解决【每一次操作都要与系统底层的数据库进行交互】

      2. 因为很明显,要解决【每一次操作都要与系统底层的数据库进行交互】就必须在服务器端开辟一块缓存区

      3. 不过如果你思考一下如何实现【每次http请求之间互相有联系】,你就会发现,它也需要在服务器端开辟一块缓存区

      4. 所以【在服务器端开辟一块缓存区】才是真正的条件,也就是说,它确实等价于【有状态】

      5. 而且我也找到了这个【在服务器端开辟一块缓存区】的条件跟前面那些官方对状态的说法对应的点,那就是:

        1. 通过在服务器端开辟一块缓存区,存储、记忆、共享一些临时数据,你就可以:
          1. 协议对于事务处理有记忆能力【事物处理】【记忆能力】
          2. 对同一个url请求有上下文关系【上下文关系】
          3. 每次的请求都是不独立的,它的执行情况和结果与前面的请求和之后的请求是直接关系的【不独立】【直接关系】
          4. 服务器中保存客户端的状态【状态】
      6. 所以,这个状态,加上前面说的客户端也有cookie,就是指,

        客户端和服务器在临时会话中产生的数据

        !而前面也说道了,使用缓存区保存临时会话中的数据是多么重要

        1. 所以状态不仅包括不同URL访问之间的关系,还有对其他URL访问的数据记录,还有一些其他的东西,所以更确切地说,状态应该是【实现了这些东西所凭借的后面的缓存空间】中的客户的临时数据
        2. cookie和session应该是完全实现了有状态这个功能

一种常见的对状态的误解:

  1. 有人在解释HTTP的无状态时,把它跟有连接对立,说是两种方式,也就是如果想不无状态,就必须有连接,但其实不然
  2. 有连接和无连接以及之后的Keep-Alive都是指TCP连接
  3. 有状态和无状态可以指TCP也可以指HTTP
  4. TCP一直有状态,HTTP一直无状态,但是应用为了有状态,就给HTTP加了cookie和session机制,让使用http的应用也能有状态,但http还是无状态
  5. 开始TCP是有连接,后来TCP无连接,再后来也就是现在TCP是Keep-Alive,有点像有连接
打赏
  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  • © 2019-2022 Zhuuu
  • PV: UV:

请我喝杯咖啡吧~

支付宝
微信