本文主题内容
- 理解 HTTP 的基本特点
- 掌握 URL 的组成与编码
- 掌握 HTTP 请求和响应格式
- 理解常用方法与状态码
- 认识常见 Header
- 理解长连接和 HTTP 版本演进
- 实现一个简单 HTTP 服务器
引言:HTTP 是浏览器、服务器和大量 Web API 之间的应用层协议。它建立在传输层之上,通过清晰的文本报文描述客户端想要什么、服务器返回了什么。
一、HTTP 基本概念
HTTP 全称 HyperText Transfer Protocol,即超文本传输协议。它是一种请求-响应协议:客户端发送请求,服务器解析请求并返回响应。
HTTP 的几个特点:
- 应用层协议,通常运行在 TCP 之上
- 报文结构清晰,HTTP/1.x 首部为文本格式
- 无状态,每次请求本身不保存之前的业务状态
- 可以通过 Cookie、Session、Token 等机制补充状态
- 能传输文本、图片、音视频和二进制文件
HTTPS 不是另一套应用语义,而是在 HTTP 与 TCP 之间加入 TLS,提供加密、身份认证和完整性保护。
二、URL
2.1 URL 组成

例:
text
https://user:pass@example.com:8443/docs/index.html?id=10#part1
可以拆分为:
- 协议:
https - 用户信息:
user:pass - 主机:
example.com - 端口:
8443 - 路径:
/docs/index.html - 查询字符串:
id=10 - 片段:
part1
片段通常只由浏览器本地处理,不会放进 HTTP 请求行发送给服务器。
2.2 URL 编码
URL 中的部分字符具有特殊含义,不能直接作为普通数据使用,需要进行百分号编码。
例:
text
+ -> %2B
空格 -> %20
中文 -> 按UTF-8编码后逐字节转成%HH
表单使用 application/x-www-form-urlencoded 时,空格也可能编码为 +,因此服务器必须根据具体上下文解码。
三、HTTP 请求
3.1 请求格式

HTTP/1.1 请求由四部分组成:
text
请求行\r\n
请求头\r\n
\r\n
请求正文
例:
http
POST /login HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: 35
Connection: keep-alive
{"name":"tom","password":"123456"}
真实 HTTP/1.x 行结尾是 \r\n,空行表示 Header 结束。
3.2 请求行
请求行包含:
text
方法 请求目标 HTTP版本
服务器通常根据方法和路径进行路由,然后根据版本决定连接和协议细节。
3.3 请求正文长度
有正文时,常使用 Content-Length 表示字节数。不能使用字符串字符数代替字节数,UTF-8 中文通常占多个字节。
HTTP/1.1 也可以使用 Transfer-Encoding: chunked 分块传输,此时不能再用普通 Content-Length 描述整个正文。
四、HTTP 响应
4.1 响应格式

响应由状态行、响应头、空行和响应正文组成。
例:
http
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 18
Connection: close
<h1>Hello</h1>
4.2 状态行
text
HTTP版本 状态码 原因短语
原因短语主要供人阅读,程序应以状态码为判断依据。
五、HTTP 方法

5.1 GET
用于获取资源。查询参数通常放在 URL 中。
http
GET /users?id=10 HTTP/1.1
Host: example.com
GET 应具有安全性和幂等性语义,也就是读取不应修改服务器状态,同一个请求执行多次的效果应一致。但是否真正做到,取决于服务端实现。
5.2 POST
常用于提交数据、创建资源或触发操作。数据一般放在请求正文中。
5.3 PUT 与 PATCH
PUT:通常表示用完整表示替换资源,具有幂等语义PATCH:通常表示部分修改资源
5.4 DELETE
用于删除资源,语义上通常是幂等的。多次删除可能返回不同状态码,但服务器最终状态一致。
5.5 HEAD 与 OPTIONS
HEAD:只返回与 GET 相同的响应头,不返回响应正文OPTIONS:查询服务器支持的方法或跨域能力
注意:方法语义不是安全机制。服务器必须独立进行身份认证和权限检查,不能因为请求使用 GET 或 POST 就默认可信。
六、HTTP 状态码

| 分类 | 含义 | 常见状态码 |
|---|---|---|
| 1xx | 信息性响应 | 100 |
| 2xx | 请求成功 | 200、201、204 |
| 3xx | 重定向或缓存 | 301、302、304、307、308 |
| 4xx | 客户端请求错误 | 400、401、403、404、405 |
| 5xx | 服务器处理错误 | 500、502、503、504 |
6.1 常见状态码
200 OK:请求成功201 Created:资源创建成功204 No Content:成功但没有正文301 Moved Permanently:永久重定向302 Found:临时重定向的传统用法304 Not Modified:缓存资源未修改400 Bad Request:请求格式或参数错误401 Unauthorized:未通过身份认证403 Forbidden:已识别请求者但没有权限404 Not Found:资源不存在500 Internal Server Error:服务器内部错误502 Bad Gateway:网关从上游得到无效响应
301、302、307、308 经常配合 Location Header 使用。307 和 308 更明确地要求重定向时保留原请求方法和正文。
七、常见 Header
7.1 Host
HTTP/1.1 请求必须提供 Host,让同一 IP 上的服务器区分不同虚拟主机。
7.2 Content-Type
描述正文媒体类型:
text
text/html; charset=utf-8
application/json
application/x-www-form-urlencoded
multipart/form-data
7.3 Content-Length
表示正文长度,单位是字节。服务端必须防止过大的长度引发内存耗尽,也要防止重复或冲突的长度字段造成请求走私风险。
7.4 Connection
keep-alive:希望复用连接close:本次响应后关闭连接
HTTP/1.1 默认支持持久连接,不能简单依赖连接关闭判断一条消息结束,必须按照报文长度或分块编码解析。
7.5 Cookie 与 Set-Cookie
服务器通过 Set-Cookie 要求浏览器保存状态,浏览器后续使用 Cookie 携带。敏感 Cookie 应合理设置 Secure、HttpOnly 和 SameSite。
八、实现简单 HTTP 服务器
下面只处理单次 GET 请求,并主动关闭连接。
例:
cpp
std::string BuildResponse(const std::string &body)
{
return "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"Content-Length: " + std::to_string(body.size()) + "\r\n"
"Connection: close\r\n"
"\r\n" + body;
}
void HandleHttp(int connfd)
{
std::string request;
char buffer[4096];
for (;;)
{
ssize_t n = recv(connfd, buffer, sizeof(buffer), 0);
if (n <= 0)
{
return;
}
request.append(buffer, static_cast<size_t>(n));
if (request.find("\r\n\r\n") != std::string::npos)
{
break;
}
if (request.size() > 64 * 1024)
{
return;
}
}
size_t lineEnd = request.find("\r\n");
std::string requestLine = request.substr(0, lineEnd);
std::string response;
if (requestLine == "GET / HTTP/1.1" || requestLine == "GET / HTTP/1.0")
{
response = BuildResponse("<h1>Hello HTTP</h1>");
}
else
{
std::string body = "<h1>404 Not Found</h1>";
response = "HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"Content-Length: " + std::to_string(body.size()) + "\r\n"
"Connection: close\r\n\r\n" + body;
}
SendAll(connfd, response.data(), response.size());
}
这个示例只用于理解格式。完整服务器还要处理:
- 请求行和 Header 的严格解析
Content-Length与 chunked 正文- 多请求持久连接
- 路径规范化,防止目录穿越
- 超时、大小限制和慢速请求
- HTTPS、认证和日志
九、HTTP 版本演进
9.1 HTTP/1.0
默认短连接,一个请求通常对应一条 TCP 连接。页面资源增多后,频繁握手带来明显开销。
9.2 HTTP/1.1
引入或完善:
- 默认持久连接
- 管道化
- Host 虚拟主机
- chunked 分块传输
- 更完善的缓存机制
管道化存在队头阻塞,实际使用并不普遍。
9.3 HTTP/2
使用二进制分帧、首部压缩和多路复用,使多个请求可以并发共享一条 TCP 连接。但 TCP 层丢包仍可能影响同一连接中的多个流。
9.4 HTTP/3
运行在 QUIC 之上,QUIC 基于 UDP 实现可靠传输、TLS 和多路复用,减少连接建立延迟,并缓解不同流之间的传输层队头阻塞。
十、总结
HTTP 使用请求-响应模型。HTTP/1.x 报文由起始行、Header、空行和可选正文组成,方法表达操作语义,状态码表达处理结果,Header 描述正文、连接、缓存和认证等属性。
URL、请求格式、响应格式、方法和状态码是使用 HTTP 的基础;持久连接、报文定界、长度限制和安全校验则决定服务器能否稳定工作。
HTTP 服务器本质上仍然是在 TCP 字节流上解析应用层协议,必须先识别完整报文,再根据方法、路径、Header 和正文完成业务处理。