一、HTTP 概述
HTTP(HyperText Transfer Protocol,超文本传输协议)作为互联网通信的重要基石,在网络通信中占据着至关重要的地位。它是一种应用层协议,工作于可靠的 TCP 协议之上,确保了数据传输的稳定性和可靠性。
HTTP 的主要特点之一是其简单、灵活且易于扩展。它被设计为人类可阅读的协议,使得开发人员在调试过程中更容易理解和排查问题,降低了新手的学习门槛。同时,HTTP 基于请求 - 响应模式工作,客户端(通常是浏览器)向服务器发送请求,服务器接收请求并返回相应的响应。
在网络通信中,HTTP 负责规定客户端和服务器之间数据传输的格式和行为。它不涉及底层的数据传输细节,而是依赖于 TCP 协议来保证数据的可靠传输。例如,当用户在浏览器中输入一个 URL 并按下回车键时,浏览器会向服务器发送 HTTP 请求,请求特定的资源,如 HTML 文档、图片、视频等。服务器接收到请求后,会根据请求的内容返回相应的资源和元数据。
HTTP 协议在发展过程中经历了多个版本的演进。从最早的 HTTP/0.9 版本,仅支持 GET 请求方法且只能传输 HTML 格式的文本,到 HTTP/1.0 版本引入了多种请求方法和更多的数据类型支持,再到 HTTP/1.1 版本的持久连接和流水线方式,提高了传输效率。如今,HTTP/2 和 HTTP/3 版本更是引入了更高效的多路复用和新的传输协议,进一步提升了性能和响应时间。
总的来说,HTTP 作为超文本传输协议,在网络通信中发挥着不可替代的作用。它的简单性、灵活性和可扩展性使其成为互联网发展的关键因素之一。
二、HTTP 的特点
(一)简单快速
HTTP 的简单快速主要体现在客户向服务器请求服务时,只需传送请求方法和路径。常用的请求方法有 GET、HEAD、POST 等。这种简洁的设计使得 HTTP 服务器程序规模小,处理请求的逻辑相对简单,因此通信速度快。例如,当用户在浏览器中输入一个网址,浏览器向服务器发送的请求可能仅仅包含一个 GET 请求方法和对应的路径,服务器接收到这个请求后,能够迅速进行处理并返回响应。
(二)灵活
HTTP 的灵活性在于它允许传输任意类型的数据对象。正在传输的类型由 Content-Type 加以标记,这使得 HTTP 可以适应各种不同的数据格式需求。无论是文本文件、图片、音频、视频还是其他复杂的数据结构,都可以通过 HTTP 进行传输。比如,在浏览网页时,页面中可能包含各种不同类型的资源,如 HTML 文件、CSS 文件、JavaScript 文件以及各种图片等,这些不同类型的资源都可以通过 HTTP 协议进行传输,Content-Type 会明确标识每个资源的类型,以便客户端正确处理。
(三)无连接
HTTP 的无连接特性是指每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。在早期,HTTP 协议产生于互联网,服务器需要处理面向全世界大量客户端的网页访问,而每个客户端与服务器之间交换数据的间歇性较大,并且两次传送的数据关联性很低。例如,一个用户在浏览网页时,可能会点击多个链接,但每个链接的请求都是独立的,服务器在处理完一个请求后就断开连接,这样可以避免长时间占用连接资源,以便更好地服务其他客户端。不过,随着网页变得越来越复杂,例如里面可能嵌入了很多图片,这种无连接的方式就显得效率较低。后来,Keep-Alive 被提出用来解决这一问题,在 HTTP1.1 协议中默认使用了 Keep Alive 模式。
(四)无状态
HTTP 协议是无状态协议,即对事务处理没有记忆能力。如果后续处理需要前面的信息,就必须重传,这可能导致每次连接传送的数据量增大。例如,用户在一个网站上进行购物,首先要登录,然后添加购物车,再下单、结算、支付等一系列操作。由于 HTTP 无状态,服务器无法记住用户的身份和之前的操作,每次请求都需要重新验证身份信息,增加了数据传输量。另一方面,在服务器不需要先前信息时,它的应答就较快。比如,用户只是单纯地请求一个静态网页,服务器不需要考虑之前的请求状态,能够快速响应。为了解决无状态的问题,出现了 Cookie 和 Session 技术,用于在客户端和服务器之间保持状态信息。
三、HTTP 请求
(一)请求结构
- 请求行包含请求方法、URI 和协议版本。
请求行是 HTTP 请求的第一行,它明确了请求的基本信息。例如,“GET /index.html HTTP/1.1” 中,“GET” 是请求方法,表示获取资源;“/index.html” 是统一资源标识符(URI),代表要获取的资源位置;“HTTP/1.1” 是协议版本。不同的请求方法有不同的用途。GET 方法通常用于获取资源,它将请求参数附加在 URL 后,数据量较小且不安全,一般不超过 1KB。而 POST 方法用于向服务器提交数据进行处理,请求参数携带在请求体中,相对安全,数据量理论上没有限制。
- 请求头传递客户端信息。
请求头由一系列键值对组成,每行一对。常见的请求头有 Accept、Content-Type、User-Agent 等。Accept 告知服务器客户端能接收的文件类型,如 “Accept: text/html” 表示客户端可以接受 HTML 文档。Content-Type 指示请求体的数据格式,比如 “Content-Type: application/json” 表示请求体是 JSON 格式的数据。User-Agent 则提供客户端的浏览器或应用程序信息,帮助服务器更好地了解请求来源。
- 空行区分请求头和请求实体。
空行在请求头之后,它的作用是明确地将请求头与请求实体分隔开来。服务器通过这个空行来判断请求头的结束位置,从而准确地解析请求内容。
- 请求实体为实际传输数据。
请求实体是请求的实际数据部分,只有在特定的请求方法(如 POST、PUT 等)下才会有请求实体。例如,在 POST 请求中,请求实体可以是表单数据、JSON 数据等,具体的数据格式由 Content-Type 头字段指定。如果是表单数据,可能以 “application/x-www-form-urlencoded” 或 “multipart/form-data” 格式传输;如果是 JSON 数据,则以 “application/json” 格式传输。
(二)请求方法
常见的 HTTP 请求方法有 GET、POST、PUT、DELETE、OPTIONS、HEAD 等。
GET 方法主要用于获取资源,它的请求参数暴露在 URL 中,传输数据量小,通常不超过 1KB,安全性较低。例如,在浏览器中输入网址获取网页内容时,就是使用 GET 方法。GET 请求可以被浏览器缓存,减少重复请求的时间。
POST 方法用于向服务器提交数据进行处理,如提交表单或上传文件。请求参数携带在请求体中,安全性相对较高。它适合用于修改数据,如创建、更新或删除资源。POST 请求通常不被缓存,因为每次请求可能会产生不同的结果。
PUT 方法用于替换指定资源的内容。例如,更新一篇文章的全部内容时可以使用 PUT 方法。PUT 方法是幂等的,即连续调用一次或多次的效果相同,没有副作用。
DELETE 方法用于删除指定的资源。比如,删除一个用户账号或一篇文章时可以使用 DELETE 方法。
OPTIONS 方法主要用于获取目标资源支持的 HTTP 方法及其他相关信息,特别是在跨域请求中用于预检。通过发送 OPTIONS 请求,客户端可以了解服务器端的支持情况,从而正确配置请求。
HEAD 方法与 GET 方法类似,但只请求资源的头部信息,不返回实际内容。可以用于检查资源的元数据,如获取资源的大小、修改时间等,而不获取实际数据。
四、HTTP 响应
(一)响应结构
- 状态行由协议版本、状态码和原因短语组成。
状态行是 HTTP 响应的第一行,它为客户端提供了关于响应的关键信息。例如,“HTTP/1.1 200 OK” 中,“HTTP/1.1” 是协议版本,“200” 是状态码,表示请求成功,“OK” 是原因短语,对状态码进行了简要描述。不同的协议版本可能会有一些细微的差异,但总体结构相似。状态码是一个三位数字,用于指示响应的类型。
- 响应头传递服务器和响应实体信息。
响应头由一系列键值对组成,提供了关于服务器和响应实体的详细信息。常见的响应头有 Content-Type、Content-Length、Server 等。Content-Type 指示响应实体的媒体类型,如 “text/html” 表示 HTML 文档,“application/json” 表示 JSON 数据。Content-Length 表示响应实体的长度,以字节为单位。Server 头字段提供了服务器软件的信息,帮助客户端了解服务器的类型和版本。
- 空行区分响应头和响应实体。
空行在响应头之后,它的作用与请求中的空行类似,用于明确地将响应头与响应实体分隔开来。客户端通过这个空行来判断响应头的结束位置,从而准确地解析响应内容。
- 响应实体存储响应信息。
响应实体是响应的实际数据部分,它可以是 HTML 文档、图片、JSON 数据等各种类型的内容。响应实体的内容和格式由响应头中的 Content-Type 字段指定。例如,如果 Content-Type 是 “text/html”,那么响应实体可能是一个 HTML 页面的代码;如果是 “application/json”,则响应实体可能是一个 JSON 格式的对象。
(二)响应状态码
HTTP 状态码分为五大类,分别是信息状态码(1xx)、请求成功码(2xx)、重定向码(3xx)、客户端错误码(4xx)和服务器错误码(5xx)。
1. 信息状态码(1xx):这类状态码表示临时响应,告诉客户端服务器已收到部分请求,请继续发送剩余部分。例如,100 Continue 状态码表示客户端发送的请求体很大时,在发送整个请求体之前,可以先发送请求的头部,并包含一个 Expect:100-continue 字段,告诉服务器大的要来了。如果服务器同意发送请求体,就返回 100 Continue 响应,指示客户端继续发送请求体。101 Switching Protocols 状态码通常用于协议升级,比如将 HTTP 协议升级成 WebSocket。
2. 请求成功码(2xx):表示客户端的请求已被成功处理。最常见的是 200 OK 状态码,表示请求已成功处理,并且响应体中包含了请求的结果。201 Created 状态码表示请求已被成功处理,并且还创建了一个新资源。例如,在提交表单创建新用户时,服务器可能会返回 201 Created 状态码,并在响应头中包含 Location 字段,指示新创建资源的位置。
3. 重定向码(3xx):表示为了完成请求,需要进一步的操作,比如跳转到新位置。301 Moved Permanently 状态码表示请求的资源已被永久移动到新的位置,客户端以后应使用新的 URI 访问该资源。302 Found 状态码表示请求的资源临时移动到了新的位置,客户端本次应使用新的 URI 访问该资源,但资源的 URI 在将来还可能变动。303 See Other 状态码表示由于请求的资源存在另外一个 URI,应该使用 GET 方法定向获取请求的资源。
4. 客户端错误码(4xx):表示请求不合法。400 Bad Request 状态码表示请求报文存在语法错误,当错误发生时,应当修改请求报文后再次发送请求。401 Unauthorized 状态码表示发送的请求需要携带认证信息,当第一次发起请求时,如果未携带认证信息,则服务器返回 401 Unauthorized,并且浏览器接收到该响应后会弹出认证用的对话窗口。404 Not Found 状态码表示服务器无法找到请求的资源。
5. 服务器错误码(5xx):表示服务器在处理请求时出现错误。500 Internal Server Error 状态码表示服务器端在执行请求时发生了错误,也有可能是 web 应用存在的 bug 或临时故障。503 Service Unavailable 状态码表示服务器现在暂时处于超负载或在进行停机维护,无法处理请求。返回响应时,如果事先知道解除以上状况所需要的时间,最好通过 Retry-After 首部字段来告知客户端。
五、URI 详解
URI(Uniform Resource Identifier)即统一资源标识符,是一个用于标识某一互联网资源名称的字符串。它可以分为 URL(Uniform Resource Locator)和 URN(Uniform Resource Name)。
(一)URI 的结构
- 基本形式:[scheme:] scheme-specific-part [#fragment]。这里分为三部分,scheme(方案)、scheme-specific-part(方案特定部分)和 fragment(片段)。
- 进一步划分:[scheme:][//authority][path][?query][#fragment]。其中,path 可以有多个,每个用 “/” 连接;query 参数可以带有对应的值,用 “=” 表示,多个 query 参数用 “&” 连接;除了 scheme 和 authority 是必须的,其他部分可以选择性地要或不要,但顺序不能变。
- 终极划分:[scheme:][//host:port][path][?query][#fragment]。其中 authority 又可以分为 host:port 的形式,冒号前的是 host(主机),冒号后的是 port(端口)。
(二)URI 的作用
URI 以某种统一的方式标识资源,允许用户对任何资源通过特定的协议进行交互操作。
(三)URL 和 URN 的区别
- URL:是 URI 的最普遍形式,即统一资源定位符。它描述了一台特定服务器上某资源的特定位置,通过协议、主机 IP 地址和资源具体地址来定位资源。例如,“https://www.example.com/page.html”,其中 “https” 是协议,“www.example.com” 是主机 IP 地址,“/page.html” 是资源具体地址。
- URN:是 URL 的一种更新形式,统一资源名称。它不依赖于位置,用于命名资源而不指定地址。例如,“urn:isbn:0-486-27557-4”,这个 URN 标识了莎士比亚的戏剧《罗密欧与朱丽叶》的某一特定版本,但没有给出资源的具体位置。
总的来说,URI 是一个广义的概念,URL 和 URN 都是其子集。URL 侧重于定位资源,而 URN 侧重于命名资源。在实际应用中,我们常常使用 URL 来访问互联网上的各种资源,而 URN 的应用相对较少,但它在一些特定的场景下,如唯一标识图书的 ISBN 系统中,发挥着重要的作用。
六、HTTP 版本演进
(一)HTTP/0.9
HTTP/0.9 是 HTTP 协议的最初版本,其功能极为简陋。在这个版本中,仅支持 GET 请求方法,意味着客户端只能向服务器请求获取资源,而无法进行其他如提交数据、删除资源等操作。同时,它只能传输 HTML 格式的文本,无法处理其他类型的数据。此外,这个版本没有 HTTP 头信息,这使得通信缺乏一些必要的元数据,如无法表明数据的类型、长度等。这种简单的设计虽然在当时的网络环境下能够满足基本的需求,但随着互联网的发展,其局限性也逐渐显现出来。
(二)HTTP/1.0
HTTP/1.0 的出现带来了重大的改进。它引入了请求头和响应头的概念,使得客户端和服务器之间的通信更加丰富和灵活。请求头可以包含诸如客户端能接受的文件类型、语言偏好等信息,而响应头则可以提供服务器的信息、资源的类型和长度等。此外,这个版本还新增了多种请求方法,如 POST 和 HEAD 等。POST 方法允许客户端向服务器提交数据进行处理,例如提交表单或上传文件。HEAD 方法则只请求资源的头部信息,不返回实际内容,可以用于检查资源的元数据。同时,HTTP/1.0 支持更多的数据类型传输,不再局限于 HTML 格式,可以根据 Content-Type 头字段传输各种格式的数据,如文本、图像、音频、视频等。这一改进使得网页可以包含丰富多样的内容,极大地推动了互联网的发展。
(三)HTTP/1.1
HTTP/1.1 在 HTTP/1.0 的基础上进一步引入了持久连接和流水线方式等新特性,极大地提高了传输效率和性能。持久连接允许在同一个 TCP 连接中发送多个请求和接收多个响应,减少了连接建立和关闭的开销。在 HTTP/1.0 中,每次请求都需要建立一个新的 TCP 连接,这在处理多个资源请求时会导致较大的延迟和资源浪费。而在 HTTP/1.1 中,默认情况下使用持久连接,除非客户端明确要求关闭连接。流水线方式则允许在第一个请求的响应还未返回时,就发送后续的请求,进一步提高了请求的发送效率。然而,HTTP/1.1 也存在一些问题,例如虽然支持持久连接和流水线方式,但在实际应用中,由于网络延迟和服务器处理顺序等原因,仍然可能会出现队头阻塞的问题,即一个请求的延迟会影响后续请求的处理。
(四)HTTP/2.0
HTTP/2.0 采用了二进制协议,与 HTTP/1.x 的文本协议相比,提高了数据传输的效率和可靠性。它引入了多路复用技术,多个往返通信都可以复用一个连接来处理,实现了资源的并行传输。这意味着可以在同一个连接上同时发送多个请求和接收多个响应,而无需等待上一个请求的响应返回后再发送下一个请求,大大提高了并发性能。此外,HTTP/2.0 使用 HPACK 算法对请求头和响应头进行了压缩,减少了传输的数据量,提高了传输速率。同时,HTTP/2.0 还可以设置请求的优先级,使得服务器可以优先处理重要的请求。另外,服务器推送也是 HTTP/2.0 的一个重要特性,服务器不再只是被动地接受请求返回响应,而是可以主动向客户端发送消息,例如在浏览器请求 HTML 的时候,服务器可以把之后可能用到的 JS、CSS 文件等预先返回给浏览器,加快首次打开页面的速度。
(五)HTTP/3.0
HTTP/3.0 基于 UDP 协议的 QUIC 协议,提升了性能和安全性。与传统的 TCP 协议相比,UDP 协议无需建立连接,减少了连接建立的延迟。QUIC 协议在 UDP 的基础上进行了改进,实现了类似 TCP 的可靠传输,但具有更低的延迟和更高的吞吐量。HTTP/3.0 继承了 HTTP/2.0 的多路复用等特性,同时进一步优化了传输性能。此外,HTTP/3.0 还加强了安全性,要求下层的通信协议必须支持前向安全和 SNI,并把弱密码套件列入 “黑名单”。然而,HTTP/3.0 也面临一些挑战,例如需要服务器和客户端的支持才能发挥其优势,目前的普及程度还相对较低。
七、HTTP 与其他协议关系
(一)与 TCP/IP 协议族
HTTP 协议属于 TCP/IP 协议族中的应用层协议。TCP/IP 协议族按层次分为应用层、传输层、网络层和数据链路层。
各层作用:
- 应用层:决定了向用户提供的应用服务和通信的活动。HTTP 协议就处于这一层,主要负责客户端和服务器之间的通信,规定了数据传输的格式和行为。例如,当用户在浏览器中输入网址时,浏览器通过 HTTP 协议向服务器发送请求,获取网页资源。
- 传输层:提供两台计算机设备之间的数据传输。其中 TCP 协议提供可靠的字节流服务,确保数据准确可靠地传输给对方。HTTP 协议依赖 TCP 协议来建立连接和传输数据。
- 网络层:主要规定数据包的传输路径,并把数据报传送给对方。IP 协议在这一层发挥重要作用,通过 IP 地址和 MAC 地址将数据包准确传送到目的地。
- 数据链路层:处理连接网络的硬件部分,包括控制操作系统、硬件的设备驱动、网卡及光纤等物理可见部分。
通信传输流:发送端从应用层往下走,接收端则从下往上走。发送端在层与层之间传递信息时一定会加上该层的首部信息,反之,接收端在层与层传递数据时,每经过一层会把首部去掉。以浏览器向服务器发送请求为例,首先在应用层,浏览器根据用户输入的网址生成 HTTP 请求,接着在传输层把从应用层收到的数据进行分割,并在各个报文上打上标记序号和端口号,然后转发给网络层。在网络层增加作为通信目的地的 MAC 地址后转发给链路层,最后链路层把数据打包成一帧帧的数据帧通过物理线路发送出去。接收端在接收到数据时会根据每一层的标记来把数据发送到指定机器上、应用上,并不断 “拆包”,最后当 HTTP 请求数据发到应用层的指定应用时才完成一次数据的请求任务。
(二)与 Cookie 技术
HTTP 协议是无状态协议,这意味着它不对之前发生过的请求和响应的状态进行管理。为了解决这个问题,引入了 Cookie 技术。
Cookie 技术通过在请求和响应报文中写入 Cookie 信息来控制客户端的状态。服务器端在响应报文中通过 Set-Cookie 字段,通知客户端保存 Cookie。当下次客户端再往该服务器发送请求时,客户端会自动在请求报文中加入 Cookie 值后发送出去。服务器端发现客户端发送过来的 Cookie 后,会去检查究竟是从哪一个客户端发来的连接请求,然后对比服务器上的记录,最后得到之前的状态信息。
Cookie 本质上就是一份存储在用户本地的文件,里面包含了每次请求中都需要传递的信息。例如,当用户登录一个网站后,服务器会在响应报文中设置一个 Cookie,里面可能包含用户的标识信息或者其他一些信息(用户名等)。用户下次访问该网站时,浏览器会自动在请求报文中加入这个 Cookie,服务器通过读取这个 Cookie 就知道用户是谁了,从而实现了状态管理。
然而,Cookie 也存在一些问题。由于 Cookie 以明文的方式存储在本地,而 Cookie 中往往带有用户信息,这样就造成了非常大的安全隐患。此外,浏览器对 Cookie 的数量和大小有限制,一般来说,Cookie 的大小限制在 4KB 左右。如果存储的数据量较大,可能会出现存储不够用的情况。
八、总结
HTTP 作为互联网通信的基石,在网络通信中起着至关重要的作用。从最初的 HTTP/0.9 版本到如今的 HTTP/3.0,HTTP 协议不断演进,以适应日益复杂的网络环境和不断增长的用户需求。
HTTP 的优点显而易见。它简单易用,语法相对简单,易于理解和实现,使得开发者可以快速构建基于 HTTP 协议的应用程序。同时,它具有良好的扩展性,能够适应各种新型的应用场景,满足不断变化的业务需求。例如,随着电子商务、在线游戏、社交媒体等互联网场景的不断发展,HTTP 协议的应用也在不断扩展。
然而,HTTP 协议也面临着一些挑战。安全性问题一直是 HTTP 协议的一大痛点。虽然引入了 HTTPS 等加密技术,但在一些安全性较弱的网络环境中,仍然存在安全风险和攻击威胁。性能问题也是 HTTP 协议需要解决的难题之一。例如,HTTP 协议的握手过程较为繁琐,且不支持持久连接,从而导致网络性能下降。此外,随着互联网的发展,HTTP 协议在处理大量并发请求时可能会变得非常慢。
尽管面临挑战,但 HTTP 协议也有着广阔的发展机遇。未来的 HTTP 协议可能会引入更高效、更安全、更智能的技术,从而实现更优质的互联网体验。例如,随着技术的不断进步,可能会出现更加先进的加密技术,确保数据传输的安全性。同时,优化性能的技术也在不断发展,如采用多路复用技术,减少延迟和优化带宽利用率。
总之,HTTP 协议在网络通信中的重要性不可忽视。虽然历经版本演进仍面临挑战,但也有着广阔的发展机遇。相信在未来,HTTP 协议将继续演进和完善,为用户带来更好的网络体验。