Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

学习HTTP系列(基础篇) #13

Open
CharlesGC opened this issue Aug 17, 2021 · 0 comments
Open

学习HTTP系列(基础篇) #13

CharlesGC opened this issue Aug 17, 2021 · 0 comments

Comments

@CharlesGC
Copy link
Owner

引言

HTTP是一种能够获取如 HTML 这样的网络资源的 protocol(通讯协议)。它是在 Web 上进行数据交换的基础,是一种 client-server 协议,也就是说,请求通常是由像浏览器这样的接受方发起的。一个完整的Web文档通常是由不同的子文档拼接而成的,像是文本、布局描述、图片、视频、脚本等等。

1. 概述

1.1 HTTP概述

HTTP被设计于20世纪90年代初期,是一种可扩展的协议。它是应用层的协议,通过TCP,或者是TLS-加密的TCP连接来发送,理论上任何可靠的传输协议都可以使用。因为其良好的扩展性,时至今日,它不仅被用来传输超文本文档,还用来传输图片、视频或者向服务器发送如HTML表单这样的信息。HTTP还可以根据网页需求,仅获取部分Web文档内容更新网页。

1.2 计算机网络体系结构分层

2. HTTP 的基本性质

2.1 特点

  1. 简单快速:虽然下一代HTTP/2协议将HTTP消息封装到了帧(frames)中,HTTP大体上还是被设计得简单易读。HTTP报文能够被人读懂,还允许简单测试,降低了门槛,对新人很友好。
  2. 灵活可扩展: 一个是语义上的自由,只规定了基本格式,其它的各部分没有严格的限制;第二个它允许传输任意类型的数据对象,例如文本、图片、音频等,传输的类型由Content-Type加以标记。
  3. 无状态:HTTP是无状态的:在同一个连接中,两个执行成功的请求之间是没有关系的。这就带来了一个问题,用户没有办法在同一个网站中进行连续的交互,比如在一个电商网站里,用户把某个商品加入到购物车,切换一个页面后再次添加了商品,这两次添加商品的请求之间没有关联,浏览器无法知道用户最终选择了哪些商品。而使用HTTP的头部扩展,HTTP Cookies就可以解决这个问题。把Cookies添加到头部中,创建一个会话让每次请求都能共享相同的上下文信息,达成相同的状态。
  • 注意,HTTP本质是无状态的,使用Cookies可以创建有状态的会话。

  1. 无状态:HTTP是无连接的,连接是由传输层控制的,HTTP并不需要其底层的传输层协议是面向连接的,只需要它是可靠的,或不丢失消息的(至少返回错误)。在互联网中,有两个最常用的传输层协议:TCP是可靠的,而UDP不是。因此,HTTP依赖于面向连接的TCP进行消息传递,但连接并不是必须的。

拓展特点: 持久连接

  • 产生原因: 在HTTP协议的初始版本中,每进行一次HTTP通信就要断开一次TCP连接。以当年的通信情况来说,因为都是些容量很小的文本传输,所以即使这样也没有多大问题。可随着 HTTP 的 普及,文档中包含大量图片的情况多了起来。比如,使用浏览器浏览一个包含多张图片的 HTML 页面时,在发送请求访问 HTML 页面资源的同时,也会请 求该 HTML 页面里包含的其他资源。因此,每次的请求都会造成无谓的 TCP 连接建立和断开,增加通信量的 开销。
  • 为解决上述 TCP 连接的问题,HTTP/1.1 和一部分的 HTTP/1.0 想出了持久连接(HTTP Persistent Connections,也称为 HTTP keep-alive 或 HTTP connection reuse)的方法。持久连接的特点是,只要任意一端没有明确提出断开连接,则保持TCP连接状态。
  • 有一个注意点: 在HTTP/1.1中所有的连接默认都是持久连接的(也就是首部字段 Connection: keep-alive,若是想要关闭则将值设置为 close),但是HTTP/1.0并未标准化

2.2 缺点

  1. 明文传输(不加密),内容可能被窃听。

    明文传输(不加密),内容可能被窃听。协议里的报文不使用二进制数据,而是文本形式

  2. 无法验证报文的完整性,内容可能被篡改。

    无法验证报文的完整性,内容可能被篡改。这里说的完整性也就是指信息的准确度 因为接收方或者发送方没有办法确认对方发送过来的数据在中间有没有被篡改

  3. 不验证通信方的身份,有可能遭遇伪装。

    不验证通信方的身份,有可能遭遇伪装。因为HTTP协议中不会对通信方进行确认 任何人都可以发送请求,而且服务器它对收到的请求也不会进行确认,只要收到了请求就会返回一个响应(当然这个只是在发送端的IP地址或者端口号没被Web服务器设定限制访问的前提下)

  4. 无状态,它是缺点也是优点吧,分不同的场景。

    • 对于一些长连接的场景需要保存上下文信息,以免传输重复的数据。
    • 对于一些应用只是为了获取数据不需要保存上下文信息,无状态减少了网络开销。
  5. 队头阻塞。

    • 其根本原因在于HTTP是基于 请求-响应 的模型,在同一个TCP长连接中,前一个请求没有得到响应,后面的请求就会被阻塞。
    • 用并发连接 和 域名分片 来解决了这个问题。但并不是从HTTP本身的层面来解决的,只是增加了 TCP 连接,分摊风险而已。
    • HTTP/2中的多路复用从HTTP本身的层面解决了这个问题
    • 和TCP队头阻塞的区别:TCP传输的单位是数据包,它的队头阻塞表示的是前一个报文没有收到便不会将下一个报文上传给HTTP。而HTTP队头阻塞是在 请求-响应 层面,前一个请求还没有处理完,后面的请求就被阻塞。

3. HTTP请求方法

3.1 方法种类

  1. GET: 请求指定的页面信息,并返回实体主体,幂等操作

  2. HEAD: 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头,幂等操作

  3. POST: 向指定资源提交数据进行处理请求(例如提交表单或者上传文件),数据被包含在请求体中,非幂等操作

  4. PUT : 从客户端向服务器传送的数据取代指定的文档的内容,幂等操作

  5. PATCH: 对资源进行局部更新,非幂等操作

  6. DELETE: 请求服务器删除指定的页面,幂等操作

  7. CONNECT: CONNECT方法建立一个到由目标资源标识的服务器的隧道

  8. TRACE: 追踪请求,查询发出去的请求是怎样被加工/篡改的,幂等操作。容易引发XST跨站追踪攻击。

  9. OPTIONS: 查询服务器端支持的HTTP方法种类(幂等操作):

    请求 OPTIONS * HTTP/1.1
    Host: lindaidai.wang
    响应 HTTP/1.1 200 OK
    Allow: GET, POST, HEAD, OPTIONS
    (返回服务器支持的方法)

3.2 GET和POST的区别

  • 从缓存的角度上说,GET会被浏览器主动缓存下来,留下历史记录,但是POST不会。
  • 从编码的角度上说,GET只能进行URL编码,它只能接收ASCII字符,但是POST没有限制。
  • 从参数的角度上说,GET一般放在URL上传递参数,POST放在请求体里,更适合传递敏感信息。
  • 从幂等的角度上说,GET是幂等的,而POST不是。
  • 不过据我了解的,其实GET和POST本质上都是TCP连接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致它们在应用过程中体现出一些不同。
  • 还有可以从TCP的角度上说,GET请求会把请求报文一次性发出去,但是POST会分为两个TCP数据包。首先发送的是header部分,若是服务器响应100(continue),则会发送body部分,当然**「火狐」**浏览器除外,它的 POST 请求只发一个 TCP 包。

3.3 服务端收到不支持的方法会如何处理

当服务端收到不支持的方法时,会返回 405 Method Not Allowed,并且会把所有支持的方法写入响应报文首部字段Allow中返回。

4. HTTP 状态码

HTTP 响应状态代码指示特定 HTTP 请求是否已成功完成。响应分为五类:信息响应(100–199),成功响应(200–299),重定向(300–399),客户端错误(400–499)和服务器错误 (500–599)。

  • 1xx:指示信息--表示请求已接收,继续处理

    「请求已经接收到,需要进一步处理才能完成,但是HTTP/1.0 不支持。」

    • 100 Continue: 这个临时响应表明,迄今为止的所有内容都是可行的,客户端应该继续请求,如果已经完成,则忽略它。

    • 101 Switching Protocols :在HTTP升级为WebSocket时,如果服务器同意变更,则返回 101。

    • 102 Processing (WebDAV): 此代码表示服务器已收到并正在处理该请求,但没有响应可用

    • 103 Early Hints: 此状态代码主要用于与Link 链接头一起使用,以允许用户代理在服务器仍在准备响应时开始预加载资源。

  • 2xx:成功--表示请求已被成功接收、理解、接受

    「成功处理请求。」

    • 200 OK :请求成功,通常返回的数据中带有响应体。

      • GET:资源已被提取并在消息正文中传输。
      • HEAD:实体标头位于消息正文中。
      • POST:描述动作结果的资源在消息体中传输。
      • TRACE:消息正文包含服务器收到的请求消息
    • 201 Created: 该请求已成功,并因此创建了一个新的资源。这通常是在POST请求,或是某些PUT请求之后返回的响应。

    • 202 Accepted: 请求已经接收到,但还未响应,没有结果。意味着不会有一个异步的响应去表明当前请求的结果,预期另外的进程和服务去处理请求,或者批处理。

    • 203 Non-Authoritative Information: 服务器已成功处理了请求,但返回的实体头部元信息不是在原始服务器上有效的确定集合,而是来自本地或者第三方的拷贝。当前的信息可能是原始版本的子集或者超集。例如,包含资源的元数据可能导致原始服务器知道元信息的超集。使用此状态码不是必须的,而且只有在响应不使用此状态码便会返回200 OK的情况下才是合适的。

    • 204 No Content:服务器成功处理了请求,但不需要返回任何实体内容,并且希望返回更新了的元信息。响应可能通过实体头部的形式,返回新的或更新后的元信息。如果存在这些头部信息,则应当与所请求的变量相呼应。如果客户端是浏览器的话,那么用户浏览器应保留发送了该请求的页面,而不产生任何文档视图上的变化,即使按照规范新的或更新后的元信息应当被应用到用户浏览器活动视图中的文档。由于204响应被禁止包含任何消息体,因此它始终以消息头后的第一个空行结尾。

    • 205 Reset Content:服务器成功处理了请求,且没有返回任何内容。但是与204响应不同,返回此状态码的响应要求请求者重置文档视图。该响应主要是被用于接受用户输入后,立即重置表单,以便用户能够轻松地开始另一次输入。与204响应一样,该响应也被禁止包含任何消息体,且以消息头后的第一个空行结束。

    • 206 Partial Content:客户端进行了范围请求且服务端正常处理,响应报文的首部应该还有Content-Range字段指定实体的范围。使用场景为HTTP分块下载和断点续传。

    • 207 Multi-Status (WebDAV): 由WebDAV(RFC 2518)扩展的状态码,代表之后的消息体将是一个XML消息,并且可能依照之前子请求数量的不同,包含一系列独立的响应代码。

    • 208 Already Reported (WebDAV): 在 DAV 里面使用: propstat 响应元素以避免重复枚举多个绑定的内部成员到同一个集合。

    • 226 IM Used (HTTP Delta encoding): 服务器已经完成了对资源的 GET 请求,并且响应是对当前实例应用的一个或多个实例操作结果的表示。

  • 3xx:重定向--要完成请求必须进行更进一步的操作

    「重定向状态,资源位置发生变动,需要重新请求。」

    • 300 Multiple Choice:被请求的资源有一系列可供选择的回馈信息,每个都有自己特定的地址和浏览器驱动的商议信息。用户或浏览器能够自行选择一个首选的地址进行重定向

    • 301 Moved Permanently:永久重定向,最新的URI为响应报文首部的 Location 字段。场景是:例如你的网站换了地址了,之前的地址不用了,若用户还是从之前的地址进的话则会返301且在Location中带上最新的URI。且浏览器默认会做缓存优化,减少服务器压力,在第二次访问的时候自动访问重定向的那个地址。

    • 302 Found:临时重定向,和301不同,它表示请求的资源临时被移动到了别的URI上,因为是暂时的,所以不会被缓存。

    • 303 See Other:临时重定向,请求的资源临时被移动到了别的URI上,但是明确表示客户端应该使用GET方法获取资源。

    • 304 Not Modefied:客户端带条件请求时虽未满足条件但是也允许返回该资源,它虽然被划分在3xx中,但其实和重定向没有关系。场景例如:协商缓存成功就会返回304 Not Modefied,表示请求的资源在服务器上并未发送改变,告诉请求者可以使用缓存。

    • 307 Temprary Redirect:临时重定向,但是比302更加明确,重定向的请求方法和实体都不允许变动。场景例如:HSTS协议,强制客户端使用https建立连接,比如你的网站从HTTP升级到了HTTPS,而你还是通过http://xxx访问的话,就会返回307 Internal Redirect

    • 308 Permanent Redirect: 这意味着资源现在永久位于由 Location: HTTP Response 标头指定的另一个 URI。 这与 301 Moved Permanently HTTP 响应代码具有相同的语义,但用户代理不能更改所使用的 HTTP 方法:如果在第一个请求中使用 POST,则必须在第二个请求中使用 POST。

    三种临时重定向简单比较:

    - `302 Found`,基本的临时重定向
    - `303 See Other`,明确表示客户端应该使用`GET`方法
    - `307 Temprary Redirect`,请求方法和实体都不允许变动
    
  • 4xx:客户端错误--请求有语法错误或请求无法实现

    「客户端出现错误。」

    • 400 Bad Request:请求报文中存在语法错误,但是没有具体指出是哪里

    • 401 Unauthorized:需要有通过HTTP认证的认证信息或者表示用户认证失败

    • 403 Forbidden:请求资源被拒绝,原因是:比如法律禁止、信息敏感

    • 404 Not Found:请求资源未找到,表示没在服务器上找到相应的资源

    • 405 Method Not Allowed: 请求行中指定的请求方法不能被用于请求相应的资源。该响应必须返回一个Allow 头信息用以表示出当前资源能够接受的请求方法的列表。 鉴于 PUT,DELETE 方法会对服务器上的资源进行写操作,因而绝大部分的网页服务器都不支持或者在默认配置下不允许上述请求方法,对于此类请求均会返回405错误。

    • 406 Not Acceptable:请求的资源的内容特性无法满足请求头中的条件,因而无法生成响应实体。

    • 407 Proxy Authentication Required: 与401响应类似,只不过客户端必须在代理服务器上进行身份验证。代理服务器必须返回一个 Proxy-Authenticate 用以进行身份询问。客户端可以返回一个 Proxy-Authorization 信息头用以验证。

    • 408 Request Timeout: 请求超时。客户端没有在服务器预备等待的时间内完成一个请求的发送。客户端可以随时再次提交这一请求而无需进行任何更改。

    • 409 Conflict: 由于和被请求的资源的当前状态之间存在冲突,请求无法完成。这个代码只允许用在这样的情况下才能被使用:用户被认为能够解决冲突,并且会重新提交新的请求。该响应应当包含足够的信息以便用户发现冲突的源头。

    • 410 Gone: 被请求的资源在服务器上已经不再可用,而且没有任何已知的转发地址。这样的状况应当被认为是永久性的。如果可能,拥有链接编辑功能的客户端应当在获得用户许可后删除所有指向这个地址的引用。如果服务器不知道或者无法确定这个状况是否是永久的,那么就应该使用 404 状态码。除非额外说明,否则这个响应是可缓存的。

    • 411 Length Required: 服务器拒绝在没有定义 Content-Length 头的情况下接受请求。在添加了表明请求消息体长度的有效 Content-Length 头之后,客户端可以再次提交该请求。

    • 412 Precondition Failed: 服务器在验证在请求的头字段中给出先决条件时,没能满足其中的一个或多个。这个状态码允许客户端在获取资源时在请求的元信息(请求头字段数据)中设置先决条件,以此避免该请求方法被应用到其希望的内容以外的资源上。

    • 413 Payload Too Large: 服务器拒绝处理当前请求,因为该请求提交的实体数据大小超过了服务器愿意或者能够处理的范围。此种情况下,服务器可以关闭连接以免客户端继续发送此请求。如果这个状况是临时的,服务器应当返回一个 Retry-After 的响应头,以告知客户端可以在多少时间以后重新尝试。

    • 414 URI Too Long: 请求的URI 长度超过了服务器能够解释的长度,因此服务器拒绝对该请求提供服务。这比较少见,通常的情况包括:本应使用POST方法的表单提交变成了GET方法,导致查询字符串(Query String)过长。

    • 415 Unsupported Media Type: 对于当前请求的方法和所请求的资源,请求中提交的实体并不是服务器中所支持的格式,因此请求被拒绝。

    • 416 Range Not Satisfiable: 如果请求中包含了 Range 请求头,并且 Range 中指定的任何数据范围都与当前资源的可用范围不重合,同时请求中又没有定义 If-Range 请求头,那么服务器就应当返回416状态码。

    • 417 Expectation Failed: 此响应代码意味着服务器无法满足 Expect 请求标头字段指示的期望值。

    • 418 I'm a teapot: 服务器拒绝尝试用 “茶壶冲泡咖啡”。

    • 421 Misdirected Request: 该请求针对的是无法产生响应的服务器。 这可以由服务器发送,该服务器未配置为针对包含在请求 URI 中的方案和权限的组合产生响应。

    • 422 Unprocessable Entity (WebDAV): 请求格式良好,但由于语义错误而无法遵循。

    • 423 Locked (WebDAV): 正在访问的资源被锁定。

    • 424 Failed Dependency (WebDAV): 由于先前的请求失败,所以此次请求失败。

    • 425 Too Early: 服务器不愿意冒着风险去处理可能重播的请求。

    • 426 Upgrade Required: 服务器拒绝使用当前协议执行请求,但可能在客户机升级到其他协议后愿意这样做。 服务器在 426 响应中发送 Upgrade 头以指示所需的协议。

    • 428 Precondition Required: 原始服务器要求该请求是有条件的。 旨在防止“丢失更新”问题,即客户端获取资源状态,修改该状态并将其返回服务器,同时第三方修改服务器上的状态,从而导致冲突。

    • 429 Too Many Requests: 用户在给定的时间内发送了太多请求(“限制请求速率”)。

    • 431 Request Header Fields Too Large: 服务器不愿意处理请求,因为它的 请求头字段太大( Request Header Fields Too Large)。 请求可以在减小请求头字段的大小后重新提交。

    • 451 Unavailable For Legal Reasons: 用户请求非法资源,例如:由政府审查的网页。

  • 5xx:服务器端错误--服务器未能实现合法的请求

    「服务端出现错误。」

    • 500 Internal Server Error:服务器内部错误,但是没有具体指出是哪里,和400有点像。

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

    • 502 Bad GateWay:服务器自身是正常的,但是代理服务器无法获取到合法响应(点外卖时外卖小哥没送)

    • 503 Service Unavailable:服务器内部处于超负载状态或进行停机维护(就像是本店今天不开张)

    • 504 Gateway Timeout: 当服务器作为网关,不能及时得到响应时返回此错误代码。

    • 505 HTTP Version Not Supported: 服务器不支持请求中所使用的HTTP协议版本。

    • 506 Variant Also Negotiates: 服务器有一个内部配置错误:对请求的透明内容协商导致循环引用。

    • 507 Insufficient Storage: 服务器有内部配置错误:所选的变体资源被配置为参与透明内容协商本身,因此不是协商过程中的适当端点。

    • 508 Loop Detected (WebDAV): 服务器在处理请求时检测到无限循环。

    • 510 Not Extended: 客户端需要对请求进一步扩展,服务器才能实现它。服务器会回复客户端发出扩展请求所需的所有信息。

    • 511 Network Authentication Required: 511 状态码指示客户端需要进行身份验证才能获得网络访问权限

5. HTTP 工作流程

HTTP通信机制是在一次完整的 HTTP 通信过程中,客户端与服务器之间将完成下列7个步骤:

1. 建立 TCP 连接

在HTTP工作开始之前,客户端首先要通过网络与服务器建立连接,该连接是通过 TCP 来完成的,该协议与 IP 协议共同构建 Internet,即著名的 TCP/IP 协议族,因此 Internet 又被称作是 TCP/IP 网络。HTTP 是比 TCP 更高层次的应用层协议,根据规则,只有低层协议建立之后,才能进行高层协议的连接,因此,首先要建立 TCP 连接,一般 TCP 连接的端口号是80;

2. 客户端向服务器发送请求命令

一旦建立了TCP连接,客户端就会向服务器发送请求命令;

例如:GET/sample/hello.jsp HTTP/1.1

3. 客户端发送请求头信息

客户端发送其请求命令之后,还要以头信息的形式向服务器发送一些别的信息,之后客户端发送了一空白行来通知服务器,它已经结束了该头信息的发送;

4. 服务器应答

客户端向服务器发出请求后,服务器会客户端返回响应;

例如: HTTP/1.1 200 OK

响应的第一部分是协议的版本号和响应状态码

5. 服务器返回响应头信息

正如客户端会随同请求发送关于自身的信息一样,服务器也会随同响应向用户发送关于它自己的数据及被请求的文档;

6. 服务器向客户端发送数据

服务器向客户端发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以 Content-Type 响应头信息所描述的格式发送用户所请求的实际数据;

7. 服务器关闭 TCP 连接

一般情况下,一旦服务器向客户端返回了请求数据,它就要关闭 TCP 连接,然后如果客户端或者服务器在其头信息加入了这行代码 Connection:keep-alive,TCP 连接在发送后将仍然保持打开状态,于是,客户端可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽。

下一篇:将分析HTTP报文结构

参考文章:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant