tomoya06 / web-developer-guidance

Actually it's just a notebook for keeping down some working experience.
4 stars 0 forks source link

Network - HTTP #8

Open tomoya06 opened 4 years ago

tomoya06 commented 4 years ago

MANUALLY FORKED FROM CS-Notes HTTP

一 、基础概念

概述

超文本传输协议(英语:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。

设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。通过HTTP或者HTTPS协议请求的资源由统一资源标识符(Uniform Resource Identifiers,URI)来标识。

HTTP协议工作于客户端-服务端架构为上。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收到的请求后,向客户端发送响应信息。

主要特点

HTTP协议有以下特点

  1. 无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
  2. 无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
  3. 简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
  4. 灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
  5. 支持B/S及C/S模式。

URI

统一资源标识符(英语:Uniform Resource Identifier,缩写:URI)在电脑术语中是一个用于标识某一互联网资源名称的字符串。

该种标识允许用户对网络中(一般指万维网)的资源通过特定的协议进行交互操作。URI的最常见的形式是统一资源定位符(Uniform Resource Locator,URL),经常指定为非正式的网址。更罕见的用法是统一资源名称(Uniform Resource Name,URN),其目的是通过提供一种途径。用于在特定的名字空间资源的标识,以补充网址。


统一资源定位符URL的标准格式如下: `[协议类型]://[服务器地址]:[端口号]/[资源层级UNIX文件路径][文件名]?[查詢]#[片段ID]` URN的标准格式如下: `urn::` ## 请求和响应报文 ### 1. 请求报文

### 2. 响应报文

# 二、HTTP 方法 客户端发送的 **请求报文** 第一行为请求行,包含了方法字段。 ## GET > 获取资源 当前网络请求中,绝大部分使用的是 GET 方法。 ## HEAD > 获取报文首部 和 GET 方法类似,但是不返回报文实体主体部分。 主要用于确认 URL 的有效性以及资源更新的日期时间等。 ## POST > 传输实体主体 POST 主要用来传输数据,而 GET 主要用来获取资源。 ### 更多 POST 与 GET 的比较 #### 作用 GET 用于获取资源,而 POST 用于传输实体主体。 #### 参数 GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,而 POST 的参数存储在实体主体中。不能因为 POST 参数存储在实体主体中就认为它的安全性更高,因为照样可以通过一些抓包工具(Fiddler)查看。 因为 URL 只支持 ASCII 码,因此 GET 的参数中如果存在中文等字符就需要先进行编码。例如 `中文` 会转换为 `%E4%B8%AD%E6%96%87`,而空格会转换为 `%20`。POST 参数支持标准字符集。 ``` 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 ``` #### 安全 安全的 HTTP 方法不会改变服务器状态,也就是说它只是可读的。 GET 方法是安全的,而 POST 却不是,因为 POST 的目的是传送实体主体内容,这个内容可能是用户上传的表单数据,上传成功之后,服务器可能把这个数据存储到数据库中,因此状态也就发生了改变。 安全的方法除了 GET 之外还有:HEAD、OPTIONS。 不安全的方法除了 POST 之外还有 PUT、DELETE。 #### 幂等性 幂等的 HTTP 方法,同样的请求被执行一次与连续执行多次的效果是一样的,服务器的状态也是一样的。换句话说就是,幂等方法不应该具有副作用(统计用途除外)。 所有的安全方法也都是幂等的。 在正确实现的条件下,GET,HEAD,PUT 和 DELETE 等方法都是幂等的,而 POST 方法不是。 GET /pageX HTTP/1.1 是幂等的,连续调用多次,客户端接收到的结果都是一样的: ``` GET /pageX HTTP/1.1 GET /pageX HTTP/1.1 GET /pageX HTTP/1.1 GET /pageX HTTP/1.1 ``` POST /add_row HTTP/1.1 不是幂等的,如果调用多次,就会增加多行记录: ``` POST /add_row HTTP/1.1 -> Adds a 1nd row POST /add_row HTTP/1.1 -> Adds a 2nd row POST /add_row HTTP/1.1 -> Adds a 3rd row ``` DELETE /idX/delete HTTP/1.1 是幂等的,即使不同的请求接收到的状态码不一样: ``` DELETE /idX/delete HTTP/1.1 -> Returns 200 if idX exists DELETE /idX/delete HTTP/1.1 -> Returns 404 as it just got deleted DELETE /idX/delete HTTP/1.1 -> Returns 404 ``` #### 可缓存 如果要对响应进行缓存,需要满足以下条件: - 请求报文的 HTTP 方法本身是可缓存的,包括 GET 和 HEAD,但是 PUT 和 DELETE 不可缓存,POST 在多数情况下不可缓存的。 - 响应报文的状态码是可缓存的,包括:200, 203, 204, 206, 300, 301, 404, 405, 410, 414, and 501。 - 响应报文的 Cache-Control 首部字段没有指定不进行缓存。 #### XMLHttpRequest 为了阐述 POST 和 GET 的另一个区别,需要先了解 XMLHttpRequest: > XMLHttpRequest 是一个 API,它为客户端提供了在客户端和服务器之间传输数据的功能。它提供了一个通过 URL 来获取数据的简单方式,并且不会使整个页面刷新。这使得网页只更新一部分页面而不会打扰到用户。XMLHttpRequest 在 AJAX 中被大量使用。 - 在使用 XMLHttpRequest 的 POST 方法时,浏览器会先发送 Header 再发送 Data。但并不是所有浏览器会这么做,例如火狐就不会。 - 而 GET 方法 Header 和 Data 会一起发送。 ## PUT > 上传文件 由于自身不带验证机制,任何人都可以上传文件,因此存在安全性问题,一般不使用该方法。 ```html PUT /new.html HTTP/1.1 Host: example.com Content-type: text/html Content-length: 16

New File

``` ## PATCH > 对资源进行部分修改 PUT 也可以用于修改资源,但是只能完全替代原始资源,PATCH 允许部分修改。 ```html PATCH /file.txt HTTP/1.1 Host: www.example.com Content-Type: application/example If-Match: "e0023aa4e" Content-Length: 100 [description of changes] ``` ## DELETE > 删除文件 与 PUT 功能相反,并且同样不带验证机制。 ```html DELETE /file.html HTTP/1.1 ``` ## OPTIONS > 查询支持的方法 查询指定的 URL 能够支持的方法。 会返回 `Allow: GET, POST, HEAD, OPTIONS` 这样的内容。 ## CONNECT > 要求在与代理服务器通信时建立隧道 使用 SSL(Secure Sockets Layer,安全套接层)和 TLS(Transport Layer Security,传输层安全)协议把通信内容加密后经网络隧道传输。 ```html CONNECT www.example.com:443 HTTP/1.1 ```

## TRACE > 追踪路径 服务器会将通信路径返回给客户端。 发送请求时,在 Max-Forwards 首部字段中填入数值,每经过一个服务器就会减 1,当数值为 0 时就停止传输。 通常不会使用 TRACE,并且它容易受到 XST 攻击(Cross-Site Tracing,跨站追踪)。 # 三、HTTP 状态码 服务器返回的 **响应报文** 中第一行为状态行,包含了状态码以及原因短语,用来告知客户端请求的结果。 | 状态码 | 类别 | 含义 | | :---: | :---: | :---: | | 1XX | Informational(信息性状态码) | 接收的请求正在处理 | | 2XX | Success(成功状态码) | 请求正常处理完毕 | | 3XX | Redirection(重定向状态码) | 需要进行附加操作以完成请求 | | 4XX | Client Error(客户端错误状态码) | 服务器无法处理请求 | | 5XX | Server Error(服务器错误状态码) | 服务器处理请求出错 | ## 1XX 信息 - **100 Continue** :表明到目前为止都很正常,客户端可以继续发送请求或者忽略这个响应。 - **101 Switching Protocol** :表示服务器应客户端升级协议的请求( Upgrade 请求头)正在切换协议。 服务器会发送一个 Upgrade 响应头来表明其正在切换过去的协议。(eg. : WebSocket协议[握手时](https://github.com/tomoya06/web-developer-guidance/issues/31)会返回) ## 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 方法。 > 301和302对SEO的影响:301永久重定向之后,搜索引擎只对新网址进行索引,同时又会把旧地址下原有的外部链接如数转移到新地址下,从而不会让网站的排名因为网址变更而收到丝毫影响;对302,目前Google会把其他域名的链接成绩计入主域,但其他搜索引擎只会把链接成绩向多个域名分摊,从而削弱主站的链接总量。 - **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 Unauthorized** :该状态码表示发送的请求需要有认证信息(BASIC 认证、DIGEST 认证)。如果之前已进行过一次请求,则表示用户认证失败。 - **403 Forbidden** :请求被拒绝。 - **404 Not Found** ## 5XX 服务器错误 - **500 Internal Server Error** :服务器正在执行请求时发生错误。 - **503 Service Unavailable** :服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。 # 四、HTTP 首部 有 4 种类型的首部字段:通用首部字段、请求首部字段、响应首部字段和实体首部字段。
各种首部字段及其含义如下(不需要全记,仅供查阅): ## 通用首部字段 | 首部字段名 | 说明 | | :--: | :--: | | Cache-Control | 控制缓存的行为 | | Connection | 控制不再转发给代理的首部字段、管理持久连接| | Date | 创建报文的日期时间 | | Pragma | 报文指令 | | Trailer | 报文末端的首部一览 | | Transfer-Encoding | 指定报文主体的传输编码方式 | | Upgrade | 升级为其他协议 | | Via | 代理服务器的相关信息 | | Warning | 错误通知 | ## 请求首部字段 | 首部字段名 | 说明 | | :--: | :--: | | 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 客户端程序的信息 | ## 响应首部字段 | 首部字段名 | 说明 | | :--: | :--: | | Accept-Ranges | 是否接受字节范围请求 | | Age | 推算资源创建经过时间 | | ETag | 资源的匹配信息 | | Location | 令客户端重定向至指定 URI | | Proxy-Authenticate | 代理服务器对客户端的认证信息 | | Retry-After | 对再次发起请求的时机要求 | | Server | HTTP 服务器的安装信息 | | Vary | 代理服务器缓存的管理信息 | | WWW-Authenticate | 服务器对客户端的认证信息 | ## 实体首部字段 | 首部字段名 | 说明 | | :--: | :--: | | Allow | 资源可支持的 HTTP 方法 | | Content-Encoding | 实体主体适用的编码方式 | | Content-Language | 实体主体的自然语言 | | Content-Length | 实体主体的大小 | | Content-Location | 替代对应资源的 URI | | Content-MD5 | 实体主体的报文摘要 | | Content-Range | 实体主体的位置范围 | | Content-Type | 实体主体的媒体类型 | | Expires | 实体主体过期的日期时间 | | Last-Modified | 资源的最后修改日期时间 |
tomoya06 commented 4 years ago

五、HTTP的具体应用

连接管理


### 1. 短连接与长连接 当浏览器访问一个包含多张图片的 HTML 页面时,除了请求访问的 HTML 页面资源,还会请求图片资源。如果每进行一次 HTTP 通信就要新建一个 TCP 连接,那么开销会很大。 长连接只需要建立一次 TCP 连接就能进行多次 HTTP 通信。 - 从 HTTP/1.1 开始默认是长连接的,如果要断开连接,需要由客户端或者服务器端提出断开,使用 `Connection : close`; - 在 HTTP/1.1 之前默认是短连接的,如果需要使用长连接,则使用 `Connection : Keep-Alive`。 ### 2. 流水线 默认情况下,HTTP 请求是按顺序发出的,下一个请求只有在当前请求收到响应之后才会被发出。由于受到网络延迟和带宽的限制,在下一个请求被发送到服务器之前,可能需要等待很长时间。 流水线是在同一条长连接上连续发出请求,而不用等待响应返回,这样可以减少延迟。 ## Cookie HTTP 协议是无状态的,主要是为了让 HTTP 协议尽可能简单,使得它能够处理大量事务。HTTP/1.1 引入 Cookie 来保存状态信息。 Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器之后向同一服务器再次发起请求时被携带上,用于告知服务端两个请求是否来自同一浏览器。由于之后每次请求都会需要携带 Cookie 数据,因此会带来额外的性能开销(尤其是在移动环境下)。 Cookie 曾一度用于客户端数据的存储,因为当时并没有其它合适的存储办法而作为唯一的存储手段,但现在随着现代浏览器开始支持各种各样的存储方式,Cookie 渐渐被淘汰。新的浏览器 API 已经允许开发者直接将数据存储到本地,如使用 Web storage API(本地存储和会话存储)或 IndexedDB。 ### 1. 用途 - 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息) - 个性化设置(如用户自定义设置、主题等) - 浏览器行为跟踪(如跟踪分析用户行为等) ### 2. 创建过程 服务器发送的响应报文包含 Set-Cookie 首部字段,客户端得到响应报文后把 Cookie 内容保存到浏览器中。 ```html HTTP/1.0 200 OK Content-type: text/html Set-Cookie: yummy_cookie=choco Set-Cookie: tasty_cookie=strawberry [page content] ``` 客户端之后对同一个服务器发送请求时,会从浏览器中取出 Cookie 信息并通过 Cookie 请求首部字段发送给服务器。 ```html GET /sample_page.html HTTP/1.1 Host: www.example.org Cookie: yummy_cookie=choco; tasty_cookie=strawberry ``` ### 3. 分类 - 会话期 Cookie:浏览器关闭之后它会被自动删除,也就是说它仅在会话期内有效。 - 持久性 Cookie:指定了过期时间(Expires)或有效期(max-age)的 Cookie。 ```html Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; ``` ### 4. 作用域 Domain 标识指定了哪些主机可以接受 Cookie。如果不指定,默认为当前文档的主机(不包含子域名)。如果指定了 Domain,则一般包含子域名。例如,如果设置 Domain=mozilla.org,则 Cookie 也包含在子域名中(如 developer.mozilla.org)。 Path 标识指定了主机下的哪些路径可以接受 Cookie(该 URL 路径必须存在于请求 URL 中)。以字符 %x2F ("/") 作为路径分隔符,子路径也会被匹配。例如,设置 Path=/docs,则以下地址都会匹配: - /docs - /docs/Web/ - /docs/Web/HTTP ### 5. JavaScript 浏览器通过 `document.cookie` 属性可创建新的 Cookie,也可通过该属性访问非 HttpOnly 标记的 Cookie。 ```html document.cookie = "yummy_cookie=choco"; document.cookie = "tasty_cookie=strawberry"; console.log(document.cookie); ``` ### 6. HttpOnly 标记为 HttpOnly 的 Cookie 不能被 JavaScript 脚本调用。跨站脚本攻击 (XSS) 常常使用 JavaScript 的 `document.cookie` API 窃取用户的 Cookie 信息,因此使用 HttpOnly 标记可以在一定程度上避免 XSS 攻击。 ```html Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly ``` ### 7. Secure 标记为 Secure 的 Cookie 只能通过被 HTTPS 协议加密过的请求发送给服务端。但即便设置了 Secure 标记,敏感信息也不应该通过 Cookie 传输,因为 Cookie 有其固有的不安全性,Secure 标记也无法提供确实的安全保障。 ### 8. 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 管理用户状态之外,还需要对用户进行重新验证,比如重新输入密码,或者使用短信验证码等方式。 ### 9. 浏览器禁用 Cookie 此时无法使用 Cookie 来保存用户信息,只能使用 Session。除此之外,不能再将 Session ID 存放到 Cookie 中,而是使用 URL 重写技术,将 Session ID 作为 URL 的参数进行传递。 ### 10. Cookie 与 Session 选择 - Cookie 只能存储 ASCII 码字符串,而 Session 则可以存储任何类型的数据,因此在考虑数据复杂性时首选 Session; - Cookie 存储在浏览器中,容易被恶意查看。如果非要将一些隐私数据存在 Cookie 中,可以将 Cookie 值进行加密,然后在服务器进行解密; - 对于大型网站,如果用户所有的信息都存储在 Session 中,那么开销是非常大的,因此不建议将所有的用户信息都存储到 Session 中。 ## 缓存 ### 1. 优点 - 缓解服务器压力; - 降低客户端获取资源的延迟:缓存通常位于内存中,读取缓存的速度更快。并且缓存服务器在地理位置上也有可能比源服务器来得近,例如浏览器缓存。 ### 2. 实现方法 - 让代理服务器进行缓存; - 让客户端浏览器进行缓存。 ### 3. Cache-Control HTTP/1.1 通过 Cache-Control 首部字段来控制缓存。 **3.1 禁止进行缓存** no-store 指令规定不能对请求或响应的任何一部分进行缓存。 ```html Cache-Control: no-store ``` **3.2 强制确认缓存** no-cache 指令规定缓存服务器需要先向源服务器验证缓存资源的有效性,只有当缓存资源有效时才能使用该缓存对客户端的请求进行响应。 ```html Cache-Control: no-cache ``` **3.3 私有缓存和公共缓存** private 指令规定了将资源作为私有缓存,只能被单独用户使用,一般存储在用户浏览器中。 ```html Cache-Control: private ``` public 指令规定了将资源作为公共缓存,可以被多个用户使用,一般存储在代理服务器中。 ```html Cache-Control: public ``` **3.4 缓存过期机制** max-age 指令出现在请求报文,并且缓存资源的缓存时间小于该指令指定的时间,那么就能接受该缓存。 max-age 指令出现在响应报文,表示缓存资源在缓存服务器中保存的时间。 ```html Cache-Control: max-age=31536000 ``` Expires 首部字段也可以用于告知缓存服务器该资源什么时候会过期。缺陷在于服务器与客户端时间可能不同步,所以出现了max-age作为替代。 ```html Expires: Wed, 04 Jul 2012 08:26:05 GMT ``` - 在 HTTP/1.1 中,会优先处理 max-age 指令; - 在 HTTP/1.0 中,max-age 指令会被忽略掉。 ### 4. 缓存验证 需要先了解 ETag 首部字段的含义,它是资源的唯一标识。URL 不能唯一表示资源,例如 `http://www.google.com/` 有中文和英文两个资源,只有 ETag 才能对这两个资源进行唯一标识。 ```html ETag: "82e22293907ce725faf67773957acd12" ``` 可以将缓存资源的 ETag 值放入 If-None-Match 首部,服务器收到该请求后,判断缓存资源的 ETag 值和资源的最新 ETag 值是否一致,如果一致则表示缓存资源有效,返回 304 Not Modified。 ```html If-None-Match: "82e22293907ce725faf67773957acd12" ``` Last-Modified 首部字段也可以用于缓存验证,它包含在源服务器发送的响应报文中,指示源服务器对资源的最后修改时间。但是它是一种弱校验器,因为只能精确到一秒,所以它通常作为 ETag 的备用方案。如果响应首部字段里含有这个信息,客户端可以在后续的请求中带上 If-Modified-Since 来验证缓存。服务器只在所请求的资源在给定的日期时间之后对内容进行过修改的情况下才会将资源返回,状态码为 200 OK。如果请求的资源从那时起未经修改,那么返回一个不带有实体主体的 304 Not Modified 响应报文。 ```html Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT ``` ```html If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT ``` ## 内容协商 通过内容协商返回最合适的内容,例如根据浏览器的默认语言选择返回中文界面还是英文界面。 ### 1. 类型 **1.1 服务端驱动型** 客户端设置特定的 HTTP 首部字段,例如 Accept、Accept-Charset、Accept-Encoding、Accept-Language,服务器根据这些字段返回特定的资源。 它存在以下问题: - 服务器很难知道客户端浏览器的全部信息; - 客户端提供的信息相当冗长(HTTP/2 协议的首部压缩机制缓解了这个问题),并且存在隐私风险(HTTP 指纹识别技术); - 给定的资源需要返回不同的展现形式,共享缓存的效率会降低,而服务器端的实现会越来越复杂。 **1.2 代理驱动型** 服务器返回 300 Multiple Choices 或者 406 Not Acceptable,客户端从中选出最合适的那个资源。 ### 2. Vary ```html Vary: Accept-Language ``` 在使用内容协商的情况下,只有当缓存服务器中的缓存满足内容协商条件时,才能使用该缓存,否则应该向源服务器请求该资源。 例如,一个客户端发送了一个包含 Accept-Language 首部字段的请求之后,源服务器返回的响应包含 `Vary: Accept-Language` 内容,缓存服务器对这个响应进行缓存之后,在客户端下一次访问同一个 URL 资源,并且 Accept-Language 与缓存中的对应的值相同时才会返回该缓存。 ## 内容编码 内容编码将实体主体进行压缩,从而减少传输的数据量。 常用的内容编码有:gzip、compress、deflate、identity。 浏览器发送 Accept-Encoding 首部,其中包含有它所支持的压缩算法,以及各自的优先级。服务器则从中选择一种,使用该算法对响应的消息主体进行压缩,并且发送 Content-Encoding 首部来告知浏览器它选择了哪一种算法。由于该内容协商过程是基于编码类型来选择资源的展现形式的,响应报文的 Vary 首部字段至少要包含 Content-Encoding。 ## 范围请求 如果网络出现中断,服务器只发送了一部分数据,范围请求可以使得客户端只请求服务器未发送的那部分数据,从而避免服务器重新发送所有数据。 ### 1. Range 在请求报文中添加 Range 首部字段指定请求的范围。 ```html GET /z4d4kWk.jpg HTTP/1.1 Host: i.imgur.com Range: bytes=0-1023 ``` 请求成功的话服务器返回的响应包含 206 Partial Content 状态码。 ```html HTTP/1.1 206 Partial Content Content-Range: bytes 0-1023/146515 Content-Length: 1024 ... (binary content) ``` ### 2. Accept-Ranges 响应首部字段 Accept-Ranges 用于告知客户端是否能处理范围请求,可以处理使用 bytes,否则使用 none。 ```html Accept-Ranges: bytes ``` ### 3. 响应状态码 - 在请求成功的情况下,服务器会返回 206 Partial Content 状态码。 - 在请求的范围越界的情况下,服务器会返回 416 Requested Range Not Satisfiable 状态码。 - 在不支持范围请求的情况下,服务器会返回 200 OK 状态码。 ## 分块传输编码 Chunked Transfer Encoding,可以把数据分割成多块,让浏览器逐步显示页面。 ## 多部分对象集合 一份报文主体内可含有多种类型的实体同时发送,每个部分之间用 boundary 字段定义的分隔符进行分隔,每个部分都可以有首部字段。 例如,上传多个表单时可以使用如下方式: ```html 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-- ``` ## 虚拟主机 HTTP/1.1 使用虚拟主机技术,使得一台服务器拥有多个域名,并且在逻辑上可以看成多个服务器。
tomoya06 commented 4 years ago

六、HTTPS

HTTP 有以下安全性问题:

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

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

加密

1. 对称密钥加密

对称密钥加密(Symmetric-Key Encryption),加密和解密使用同一密钥。

常见的对称加密算法有AES、ChaCha20、3DES、Salsa20、DES、Blowfish、IDEA、RC5、RC6、Camellia。

2.非对称密钥加密

非对称密钥加密,又称公开密钥加密(Public-Key Encryption),加密和解密使用不同的密钥。公开密钥所有人都可以获得,消息可以用公钥加密,只有密钥拥有者能解开。

非对称密钥除了用来加密,还可以用来进行签名。因为私有密钥无法被其他人获取,因此通信发送方使用其私有密钥进行签名,通信接收方使用发送方的公开密钥对签名进行解密,就能判断这个签名是否正确。

常见的非对称加密算法有:椭圆曲线数字签名算法

2.1 数字签名

数字签名技术是将原文通过特定HASH函数得到的摘要信息,然后用发送者的私钥加密,与原文一起传送给接收者。接收者只有用发送者的公钥才能解密被加密的摘要信息,然后用HASH函数对收到的原文提炼出一个摘要信息,与解密得到的摘要进行对比。

简而言之,数字签名 = 私钥加密过的原文哈希

3. HTTPS 采用的加密方式

认证

数字证书认证机构(CA,Certificate Authority)是客户端与服务器双方都可信赖的第三方机构。通信双方通过使用CA办法的 证书 来对通信方进行认证,证书上面包含公钥以及公钥签名。

CA也有一套自己的公钥密钥,浏览器会内置各大CA的公钥。服务器向 CA 提出公开密钥的申请,CA生成一对公钥密钥之后,会用自己的密钥对公开密钥做数字签名,然后将这个已签名的公开密钥放入证书,发给服务器。

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

完整性保护

SSL 提供报文摘要功能来进行完整性保护。

HTTP 也提供了 MD5 报文摘要功能,但不是安全的。例如报文内容被篡改之后,同时重新计算 MD5 的值,通信接收方是无法意识到发生了篡改。

HTTPS 的报文摘要功能之所以安全,是因为它结合了加密和认证这两个操作。试想一下,加密之后的报文,遭到篡改之后,也很难重新计算报文摘要,因为无法轻易获取明文。

完整握手过程

详细参考这里

image

参与角色

过程步骤概述

过程叙述参考知乎专栏

第一步:客户端向服务端发起请求

  1. 客户端生成随机数R1 发送给服务端;
  2. 告诉服务端自己支持哪些加密算法;

第二步:服务器向客户端发送数字证书

  1. 服务端生成随机数R2;
  2. 从客户端支持的加密算法中选择出双方都支持的加密算法(此算法用于后面的会话密钥生成);
  3. 服务端生成把证书、随机数R2、会话密钥生成算法,一同发给客户端;

第三步:客户端验证数字证书

  1. 验证证书的可靠性,先用CA的公钥解密被加密过后的证书,能解密则说明证书没有问题,然后通过证书里提供的摘要算法进行对数据进行摘要,然后通过自己生成的摘要与服务端发送的摘要比对。
  2. 验证证书合法性,包括证书是否吊销、是否到期、域名是否匹配,通过后则进行后面的流程
  3. 获得证书的公钥、会话密钥生成算法、随机数R2
  4. 生成一个随机数R3。
  5. 根据会话秘钥算法使用R1、R2、R3生成会话秘钥。
  6. 用服务端证书的公钥加密随机数R3并发送给服务端。

第四步:服务器得到会话密钥

  1. 服务器用私钥解密客户端发过来的随机数R3
  2. 根据会话秘钥算法使用R1、R2、R3生成会话秘钥

第五步:客户端与服务端进行加密会话

  1. 解密接收数据:用会话密钥解密对方发送的数据;
  2. 加密响应数据:用会话密钥把响应的数据加密发送给对方。

HTTPS 的缺点

tomoya06 commented 4 years ago

HTTP/1.0特性

缺点:

HTTP/1.1 新特性

七、HTTP/2.0

参考Google博客

二进制分帧层

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


在通信过程中,只会有一个 TCP 连接存在,它承载了任意数量的双向数据流(Stream)。 - 一个数据流(Stream)都有一个唯一标识符和可选的优先级信息,用于承载双向信息。 - 每个数据流都有一个唯一的标识符和可选的优先级信息,用于承载双向消息。 - 每条消息都是一条逻辑 HTTP 消息(例如请求或响应),包含一个或多个帧。 - 帧(Frame)是最小的通信单位,帧头会标识所属的数据流。来自不同数据流的帧可以交错发送,然后再根据数据流标识符重新组装。

## 【主要区别】多路复用 见上图,基于二进制分帧,在同一域名下所有访问都是从同一个tcp连接中走,http消息被分解为独立的帧,乱序发送,服务端根据标识符和首部将消息重新组装起来 > HTTP/1.1不能多路复用的原因:1.1还是通过文本而非二进制进行传输,没有流的概念。接收端不能区分相应对应的请求,所以也无法重新组装;此外HTTP1.1是序列和阻塞机制。 ## 服务端推送 HTTP/2.0 在客户端请求一个资源时,会把相关的资源一起发送给客户端,客户端就不需要再次发起请求了。例如客户端请求 page.html 页面,服务端就把 script.js 和 style.css 等与之相关的资源一起发给客户端。

> 配置方式:nginx可以设置`http2_push`来设置某一路由请求时主动推送的文件。参考[nginx文档](https://www.nginx.com/blog/nginx-1-13-9-http2-server-push/)以及[nginx篇issue](https://github.com/tomoya06/web-developer-guidance/issues/27#issuecomment-701137914) ## 首部压缩 HTTP/1.1 的首部带有大量信息,而且每次都要重复发送。HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之前见过的首部字段表,从而避免了重复传输。 不仅如此,HTTP/2.0 也使用 Huffman 编码对首部字段进行压缩。

## 安全性 > 本段参考[博客](https://www.ssl.com/article/an-introduction-to-http2/) http2.0协议本身不强制要求使用SSL层加密,不过主流浏览器大多都只支持HTTPS/2.0,这也要求使用HTTP/2.0的开发者也要将服务升级到SSL/TSL支持。
tomoya06 commented 4 years ago

同源策略与跨域请求

同源策略

定义

定义:如果两个 URL 的 protocol、port (如果有指定的话)和 host 都相同的话,则这两个 URL 是同源。这个方案也被称为“协议/主机/端口元组”,或者直接是 “元组”。

image

运用

CORS

定义:跨域资源共享(cross-origin resource sharing)是一种机制,它使用额外的 HTTP 头来告诉浏览器,让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。

CORS请求

CORS 请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。只要同时满足以下两大条件,就属于简单请求:

  1. 请求方法是以下三种方法之一:HEAD / GET / POST
  2. HTTP 的头信息不超出以下几种字段:
    • Accept / Accept-Language / Content-Language / Last-Event-ID
    • Content-Type,且只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

凡是不同时满足上面两个条件,就属于非简单请求。

需要CORS的情况

请求流程

本段参考阮一峰的博客

简单请求

对于简单请求,浏览器直接发出 CORS 请求,并在头信息之中增加一个Origin字段。

如果Origin在许可范围内,服务器返回的相应会多出以下响应头:

  1. 必选相应头:Access-Control-Allow-Origin: *或指定特定域名,来限制可访问的域名
  2. 可选:Access-Control-Allow-Credentials,它的值是一个布尔值,表示是否允许发送 Cookie。
  3. 可选:Access-Control-Expose-Headers,表示可从报文中读取的响应头字段

浏览器如果发现,回应的头信息没有包含Access-Control-Allow-Origin字段、或不在允许Origin范围内,就会抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。

非简单请求和预检请求

非简单请求的 CORS 请求,会在正式通信之前,增加一次 OPTIONS方法的 HTTP 查询请求,称为“预检”请求。

预检请求头包含以下字段:

  1. 必选:Access-Control-Request-Method,列出浏览器的 CORS 请求会用到哪些 HTTP 方法
  2. 可选:Access-Control-Request-Headers,一个逗号分隔的字符串,指定浏览器 CORS 请求会额外发送的头信息字段

预检请求的响应头包含以下字段:

  1. Access-Control-Allow-Origin
  2. Access-Control-Allow-Methods
  3. Access-Control-Allow-Headers
  4. Access-Control-Allow-Credentials
  5. 可选:Access-Control-Max-Age,指定本次预检请求的有效期,单位为秒

同上,如果预检时Origin或其他请求设置不合法,浏览器也会报错。如果合法,就发送正常的非简单请求,当然也会带上Origin字段。

tomoya06 commented 4 years ago

网络攻击与网络安全

Egg框架文档中详细地提供了各种攻击方式的简介和Egg的防范方式,可以参考阅读

跨站脚本 (cross-site scripting, XSS)

恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。

案例:通过输入框往html中插入<script>alert(“hey!you are attacked”)</script>

防御:输入文本过滤、输出文本转义或编码

跨站请求伪造 (cross-site request forgery, CSRF)

攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并运行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去运行。

防御:接口引入token验证、检查请求头Referer判断请求来源

中间人攻击

如果只用公私钥对来进行加密,没有证书或者公钥签名,攻击者可以介入server和client中间拦截,用自己的公私钥匙分别与双方通信,让对方都正在跟对方正常通信。HTTPS协议中CA的介入就可以解决这个问题。

DDoS

拒绝服务攻击(英语:denial-of-service attack,简称DoS攻击)亦称洪水攻击,是一种网络攻击手法,其目的在于使目标电脑的网络或系统资源耗尽,使服务暂时中断或停止,导致其正常用户无法访问。

攻击方式

更多攻击方式参考维基百科

防御方式