C#网络编程(三)----HTTP协议

HTTP协议

HTTP(超文本传输协议),属于应用层协议。基于TCP连接实现。但通信方向始终由客户端发起(HTTP/2之后已修改)

维度 TCP/IP协议族(传输层/TCP) HTTP协议(应用层)
通信方向 全双工(双向同时通信) 单向(客户端→服务器请求,服务器响应)
协议层次 传输层(负责数据传输可靠性) 应用层(定义数据格式和业务逻辑)
典型场景 基础网络通信(如文件传输、邮件) 客户端获取服务器资源(如网页访问)
主动通信能力 双方均可主动发送数据 仅客户端可主动发起请求

HTTP报文结构

分为请求报文与响应报文,但结构类似,都由报文首部,空行(标识首部结束)与报文主体。
请求报文:

复制代码
/*HTPP协议的版本*/
GET / HTTP/1.1
/*客户端支持的内容类型*/
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
/*客户端支持的内容编码类型*/
Accept-Encoding: gzip, deflate, br, zstd
/*客户端支持的语言*/
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
/*缓存控制,0代表不使用缓存*/
Cache-Control: max-age=0
/*连接方式,keep-alive即持久连接*/
Connection: keep-alive
/*请求的主机名*/
Host: www.baidu.com

响应报文

复制代码
/*HTTP协议版本及状态码,表明使用HTTP/1.1协议,请求成功*/
HTTP/1.1 200 OK
/*连接方式,保持TCP连接持久化,便于后续请求复用连接*/
Connection: keep-alive
/*响应内容的编码方式,使用gzip压缩*/
Content-Encoding: gzip
/*响应内容的类型及字符编码,内容为HTML,编码是UTF-8*/
Content-Type: text/html; charset=utf-8
/*服务器生成响应的时间(格林尼治标准时间)*/
Date: Sun, 27 Apr 2025 04:11:28 GMT
/*服务器软件信息,使用百度Web服务器,版本1.1*/
Server: BWS/1.1
/*设置Cookie,H_PS_PSSID用于存储用户会话标识,指定路径、过期时间和域名*/
Set-Cookie: H_PS_PSSID=61027_61673_62325_62337_62831_62863_62877_62885_62928_62969_63040_63050_63073; path=/; expires=Mon, 27-Apr-26 04:11:28 GMT; domain=.baidu.com
/*设置Cookie,BDSVRTM用于百度统计相关,指定路径*/
Set-Cookie: BDSVRTM=5; path=/
/*设置Cookie,BD_HOME标识是否为百度首页访问,指定路径*/
Set-Cookie: BD_HOME=1; path=/
/*启用严格传输安全,强制浏览器在一定时间(172800秒)内通过HTTPS连接*/
Strict-Transport-Security: max-age=172800
/*百度内部请求追踪ID,用于全链路性能监控和问题定位*/
Traceid: 1745727088348548045813596150688561061649
/*建议浏览器使用Edge或Chrome内核渲染页面,提升兼容性*/
X-Ua-Compatible: IE=Edge,chrome=1
/*启用跨站脚本攻击防护,当检测到可疑脚本时直接阻止渲染*/
X-Xss-Protection: 1;mode=block
/*响应采用分块传输,大文件分段发送以提升传输可靠性*/
Transfer-Encoding: chunked

报文主体(可选)

具体的响应内容,不一定要有值。比如204 No Content状态码的响应

复制代码
<html>
    <head>
        <meta name="description" content="全球领先的中文搜索引擎、致力于让网民更便捷地获取信息,找到所求。百度超过千亿的中文网页数据库,可以瞬间找到相关的搜索结果。">
        <title>百度一下,你就知道</title>
	</head>
	<body>
	</body>
</html>

HTTP各版本之间的区别

HTTP/0.9

HTPP协议的第一个版本,诞生于1991年。是一种非常简单的协议,主要用于传输纯文本HTML页面。

功能很单一,只支持GET请求。属于三无产品,无请求头,无响应头,无状态码。

HTTP/1.0

为了解决上述缺点,于1996年发布了HTTP/1.0版。

引入了POST/HEAD等方法,丰富了交互方式;

引入了请求头与响应头,实现了与正文的解耦;

引入了状态码,用于表示请求结果;

HTTP/1.0默认短连接,每一个请求都是独立的握手/挥手的过程,每个HTTP请求完成后,连接都会被关闭,效率很低。

如果你打开一个网页,该网页有10000个CSS/JS ,那么将会瞬间占满整个服务器资源。

HTTP/1.1

为了进一步优化性能和功能,随即在1997年发布了HTTP/1.1版
默认持久连接: keep-alive,允许一个TCP连接上发送多个请求和响应,减低了服务器监听TCP连接的压力,提高传输效率;
请求头压缩: 通过压缩请求头,减少请求头大小,降低传输压力。
分块传输: Transfer - Encoding: chunked 允许服务器在数据未完全生成时就开始传输,提高效率。
缓存机制: Cache - Control、ETag
虚拟主机: Host,允许服务器托管多个域名。
**Method增强:**新增PUT,DELET,OPTIONS等方法请求

google浏览器默认为一个域名建立6条连接,所有文件传输都使用这六条连接复用。
常见优化思路:

  1. 减少请求数量
    将资源文件(css,js等)合并
  2. 增减连接数量
    将资源分散到不同域名下,以绕开浏览器对同一个域名的最大连接限制。
    HTTP性能的关键在于低延迟而不是高宽带,以上优化,治标不治本。并没有完全解决这些问题。

HTTP/2

随着互联网发展,移动互联网与高并发场景的增加。HTTP/1.1逐渐暴露了性能瓶颈,在2015年发布了HTTP/2版本。

HTTP/2抽象出了Stream的概念,实现了并发传输,一个Stream就相当于HTTP/1.1的请求和响应

  1. 二进制分帧:

    HTTP/1.1 以纯文本传输数据(如请求行、头部、实体),解析效率低且易出错;

    HTTP/2 将所有数据(包括请求、响应、头部、实体)分割为 二进制帧(Frame),二进制格式更紧凑、解析更快,且消除了文本解析的歧义

  2. 多路复用:

    HTTP/1.1 依赖多个 TCP 连接或长连接(Keep-Alive)处理并发请求,但存在 队头阻塞。HTTP/2 通过 单个 TCP 连接 同时发送多个请求 / 响应,每个请求 / 响应称为一个 流(Stream),以唯一 ID 区分,帧可交错传输,接收端按流重组数据

  3. 头部压缩:

    HTTP/2 使用 HPACK 算法,通过 静态字典(预定义常用头部)和 动态字典(记录此次连接中出现的新头部)对头部进行压缩,减少传输数据量。

  4. 服务器推送:

    服务端可以主动向客户端推送资源,提前将客户端可能需要的资源发送给客户端,减少等待时间。

    比如客户端请求 index.html,服务器在响应 HTML 的同时,推送页面所需的 style.css 和 script.js,减少客户端的往返时间(RTT)。

HTTP2在应用层与传输层之间增加了二进制分帧层,将HTTP协议由文本协议转为了二进制协议。从而实现乱序请求与响应,之前的文本协议是做不到的。

HTTP/3

尽管 HTTP/2 解决了 HTTP/1.1 的一些性能问题,但它仍然依赖于 TCP 协议,而 TCP 协议存在一些固有的缺陷,如TCP队头阻塞,握手挥手成本较大等问题。为了解决这些问题,在 2022 年发布了 HTTP/3 版本。

HTTP/3 放弃了 TCP,转而基于 QUIC(Quick UDP Internet Connections),这是其与 HTTP/2 的根本区别。QUIC 是一个运行在 UDP 之上的通用传输层协议,集成了传输控制、加密和多路复用功能

  1. 基于 UDP 的快速连接建立:

    HTTP/2摆脱不了TCP,建立握手需要2-3个RTT,而QUIC只需要一个RTT

  2. 无队头阻塞的多路复用:

    HTTP/2虽然在应用层实现了多路复用,但受限于 TCP 单个连接,若 TCP 数据包丢失,滑动窗口无法向前移动,因此所有流都会阻塞。

    QUIC则是给每个Stream都分配了一个独立的滑动窗口,这样使得同一个连接数的多个Stream之间没有依赖关系,互联独立控制滑动窗口,从而实现真正意义上的多路复用。

  3. 改进的拥塞控制与可靠性:

    QUIC 使用 版本化的 ACK 机制,精确记录每个数据包的接收情况,避免 TCP 因序列号混乱导致的误判。支持多种算法(如 Cubic、BBR),并可动态调整,适应高丢包率网络(如移动蜂窝网络)。

  4. 内置加密与安全:

    QUIC 继承 TLS 1.3 的加密能力,所有传输数据(包括握手过程和载荷)均经过加密,避免中间设备篡改或监听。

    TLS 1.3 的简化握手流程与 QUIC 深度整合,减少加密带来的性能损耗。

为什么不升级TCP协议而是QUIC协议? Fast Open可以缩短连接建立时间,BBR算法可以避免拥塞和滑动窗口阻塞问题。这些都可以大大提高TCP协议的处理速度。

主要原因在于历史包袱,因为TCP协议的处理和由操作系统内核来实现的,所以海量的旧设备无法享受到新技术带来的便利。

特性 HTTP/1.1 HTTP/2 HTTP/3 (QUIC)
发布时间 1997年(RFC 2616,后续修订) 2015年(RFC 7540) 2022年(RFC 9000,基于 QUIC)
应用层协议 基于 TCP 基于 TCP 基于 UDP(通过 QUIC 实现可靠传输)
传输层协议 TCP TCP UDP + QUIC 协议(内置 TLS 加密)
多路复用 每个请求单独建立 TCP 连接, 通过 Connection: keep-alive 复用连接, 但存在连接级队头阻塞(同一连接中请求需按顺序处理) 二进制分帧(Binary Framing), 单个 TCP 连接中多路复用多个请求/响应, 消除连接级队头阻塞 ,但流内仍有队头阻塞 QUIC 基于 UDP,每个流(Stream)独立传输, 流之间互不阻塞, 完全消除连接级和流级队头阻塞
头部压缩 无专用头部压缩,仅支持 gzip 等通用压缩(开销大) 引入 HPACK 算法,对头部字段进行索引和霍夫曼编码,大幅减少头部开销 基于 QUIC 的头部压缩(类似 HPACK), 支持动态表管理,压缩效率与 HTTP/2 相近
连接建立 TCP 三次握手(1 RTT), TLS 需额外 1-2 RTT(如 TLS 1.2) TCP 三次握手(1 RTT), TLS 通过 ALPN 协商(1 RTT,TLS 1.3 优化后) QUIC 握手集成 TLS 加密, 首次连接 1 RTT, 会话恢复可实现 0 RTT(安全模式下有限制)
安全性 明文传输(HTTPS 需额外 TLS 层), 默认不加密 支持明文(http://),但推荐 HTTPS(https:// 强制加密 (基于 TLS 1.3,QUIC 内置加密), 无明文传输模式
流控制 基于 TCP 协议的流控制(窗口机制) 新增 HTTP 层流控制, 支持连接级和流级独立控制(窗口机制) QUIC 层流控制(基于 UDP 的窗口机制), 更精细的流和连接级控制
优先级与依赖处理 无显式优先级,资源按请求顺序加载 支持请求优先级(通过流优先级标记), 允许服务器优先处理关键资源 继承 HTTP/2 的优先级机制, 基于 QUIC 流的优先级管理
队头阻塞 连接级和请求级均存在(同一连接中请求阻塞会影响后续请求) 连接级消除 ,但流内请求仍可能阻塞(单个流内包丢失会阻塞该流) 完全消除(每个流独立,流间包丢失不互相影响)
协议升级方式 无内置升级机制,需手动切换(如 HTTP 到 HTTPS) 通过 ALPN(Application-Layer Protocol Negotiation)在 TLS 握手时协商升级 通过 QUIC 版本协商(UDP 端口 443,兼容现有防火墙), 支持动态版本更新
错误恢复与重传 依赖 TCP 的重传机制(慢启动、拥塞控制) 同 TCP 机制, 但 HTTP/2 帧级重传需依赖 TCP 层 QUIC 内置多路复用和独立流控制, 单个流的包丢失仅重传该流数据, 拥塞控制更灵活(如 ECMP 多路径传输)
服务器推送 不支持 支持(Server Push),可主动推送资源到客户端 理论上支持,但 QUIC 层未显式定义, 实际应用较少
默认端口 80(明文)、443(HTTPS) 80(明文)、443(HTTPS)(与 HTTP/1.1 兼容) 443(强制加密,复用 HTTPS 端口, 也可支持其他端口,但推荐 443)
适用场景 老旧系统、低并发场景 高并发网站、需要减少延迟的场景(如单页应用) 高延迟或网络不稳定环境(如移动网络、物联网), 追求极速连接和低延迟的场景
主要优势 兼容性强,实现简单 减少连接数、降低延迟、提升吞吐量 更快的连接建立、抗网络拥塞、消除队头阻塞
主要劣势 高延迟、队头阻塞严重、头部开销大 仍依赖 TCP,受限于 TCP 固有缺陷(如队头阻塞在流内残留) 基于 UDP,可能受防火墙限制, 实现复杂度高

HTTP请求方式

方法 作用 场景 是否幂等
GET 请求资源,无请求体(并不强制) 页面浏览,API数据查询 幂等,多次请求结果一致,不修改服务器状态
POST 提交数据,有请求头 登录,评论等创建资源行为 非幂等,多次请求创建多个资源
PUT 更新资源,全量更新 文件内容替换 幂等,全局替换,资源最终状态一致
PATCH 更新资源,部分更新 更新用户名,修改密码,更新订单状态 非幂等,可能包含增量,比如修改次数等,多次执行结果可能不同
DELETE 删除指定资源 删除博客,删除订单,用户注销 幂等,最终状态均为不存在
HEAD 仅获取响应头部(不返回主体) 检查资源是否存在及元信息 幂等,仅获取响应头,不修改服务器
OPTIONS 查看服务器支持的HTTP方法 请求前的检查 幂等,用于查询服务器支持的请求方法和跨域配置,不修改服务器
CONNECT 建立一个到目标资源的隧道 用于在客户端和服务器之间进行加密的隧道传输,.通常用于 SSL/TLS 代理 未定义,仅用于建立隧道,理论上是幂等
TRANCE 显示服务器收到的请求 主要用于测试与调试,大多数服务器都会禁用TRANCE 幂等,仅回显,不修改服务器

HTTP响应码

基于 **RFC 7231/7232/7233 等规范

类别 含义 首位数字 典型场景
信息性 请求已接收,继续处理 1xx 101 Switching Protocols(协议升级)
成功 请求已成功处理 2xx 200 OK201 Created
重定向 需要进一步操作以完成请求 3xx 301 Moved Permanently302 Found
客户端错误 请求存在语法错误或无法处理 4xx 404 Not Found403 Forbidden
服务器错误 服务器处理请求时发生错误 5xx 500 Internal Server Error

1xx 信息性状态码(Informational)

状态码 名称 说明
100 Continue 客户端请求的前半部分已接收,可继续发送剩余部分(如分块上传)。
101 Switching Protocols 服务器同意切换协议(如从 HTTP 切换到 WebSocket,通过 Upgrade 头)。
103 Early Hints (HTTP/2+)服务器提前返回提示信息(如资源预加载),用于优化性能。

2xx 成功状态码(Successful)

状态码 名称 说明
200 OK 请求成功,返回请求的数据(最常用)。
201 Created 请求成功并创建新资源(如通过 POST 创建用户,返回资源 URI)。
204 No Content 请求成功但无返回内容(常用于删除操作或无需响应体的场景,如 DELETE)。
206 Partial Content 客户端请求部分内容(如 Range 头分块下载),返回指定范围的数据。
202 Accepted 请求已接收但尚未处理(用于异步处理场景,如后台任务提交)。

3xx 重定向状态码(Redirection)

状态码 名称 说明
301 Moved Permanently 资源永久转移,后续请求应使用新 URI(浏览器会缓存新地址)。
302 Found 资源临时转移,客户端应使用原 URI 重新请求(HTTP/1.1 规范已更名为 302 Found,原 302 Moved Temporarily 弃用)。
303 See Other 请求的响应需通过 GET 方法访问另一个 URI(常用于表单提交后跳转)。
304 Not Modified 资源未修改,可使用缓存内容(需配合 If-None-Match/If-Modified-Since 头)。
307 Temporary Redirect 临时重定向,保留原始请求方法(如 POST 重定向后仍用 POST 访问新 URI)。
308 Permanent Redirect 永久重定向,保留原始请求方法(替代旧版 301 的非标准行为)。

4xx 客户端错误状态码(Client Errors)

状态码 名称 说明
400 Bad Request 客户端请求语法错误(如错误的 JSON 格式、无效参数)。
401 Unauthorized 请求需要身份验证(如缺少 Authorization 头,或令牌无效)。
403 Forbidden 服务器拒绝请求(即使身份验证通过,权限不足,如无访问资源的权限)。
404 Not Found 请求的资源不存在(URI 错误或资源已删除)。
405 Method Not Allowed 服务器不支持请求的方法(如对仅支持 GET 的端点使用 POST)。
409 Conflict 请求与资源当前状态冲突(如创建同名用户时的唯一约束冲突)。
410 Gone 资源已永久删除(比 404 更明确,提示用户无需再尝试)。
413 Payload Too Large 请求体过大(超过服务器限制,需配合 Content-LengthTransfer-Encoding 头)。
414 URI Too Long URI 过长(常见于手动构造的超长 URL)。
429 Too Many Requests 客户端请求频率过高,触发限流(需配合 Retry-After 头告知重试时间)。
431 Request Header Fields Too Large 请求头字段过长(如 Cookie 过大),服务器拒绝处理。

5xx 服务器错误状态码(Server Errors)

状态码 名称 说明
500 Internal Server Error 服务器内部错误(通用错误码,用于未知或未处理的异常)。
501 Not Implemented 服务器不支持请求的功能(如未实现的 API 端点)。
502 Bad Gateway 代理服务器收到无效的上游响应(如上游服务器崩溃)。
503 Service Unavailable 服务器暂时不可用(如维护模式,需配合 Retry-After 头)。
504 Gateway Timeout 代理服务器等待上游服务器超时(与 502 类似,侧重超时)。

RESTFUL个人使用经验(未必正确)

在实践RESTFUL过程中,如果严格按照RESTFUL标准,无疑增加与前端对接的成本。

约定优于配置,因此团队内部只使用几个特定状态码,避免没有必要的沟通。

200:表示成功,响应中会返回具体信息,不再区分200,201,204

304:API缓存,响应中会返回具体信息。

400:业务异常,响应中会返回具体信息,401,403状态码由Gateway处理,微服务不再鉴权重复鉴权。

500:服务器异常
其它冷门状态码会被Gateway所处理

番外

Socket与Websocket的区别?

Socket 是网络编程的一个抽象概念,一套标准。借助Socket,开发者能够在不同主机间实现通信,屏蔽细节。它的主流实现都是基于TCP/IP协议。
WebSocket 则是建立在HTTP协议之上,由 HTML5 提出,目的是为了解决HTTP协议只能单向通信的问题,属于应用层协议。

GET请求长度限制?

GET请求有最大长度限制,这是一个流传很久的都市谣言

事实上,W3C组织从来没有对GET长度做出要求,真正限制GET长度的是浏览器(IE,Chrome,FireFox)与服务器(Nginx,Tomcat,Kestrel)。

目前使用最广泛的HTTP协议?

https://w3techs.com/technologies/history_overview/site_element/all

截至 2025 年,全球前 1000 大网站中约 30% 已部署 HTTP/3,主要集中在大型 CDN 和对性能敏感的应用(如 Google、Netflix),但仍低于 HTTP/2 的普及率(约 80%)