【Linux】应用层协议HTTP

本文主题内容

  • 理解 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 默认支持持久连接,不能简单依赖连接关闭判断一条消息结束,必须按照报文长度或分块编码解析。

服务器通过 Set-Cookie 要求浏览器保存状态,浏览器后续使用 Cookie 携带。敏感 Cookie 应合理设置 SecureHttpOnlySameSite

八、实现简单 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 和正文完成业务处理。

相关推荐
k4m7v2pz31 分钟前
多开云网页操作指南(供豆包云电脑 / 自动化 Agent 执行)
运维·自动化·电脑
dunge202637 分钟前
ChatGPT Plus / Pro + Codex 深度实战指南:2026年9月2日 从智能编程到自动化工作流的完整技术手册
运维·chatgpt·自动化
M78佐菲9 小时前
Linux学习笔记:TCP协议
linux·笔记·学习·tcp/ip·算法
Brilliantwxx9 小时前
【Linux】 进程(9)程序与进程地址空间(基础+进阶+面试题)
linux·运维·服务器·开发语言·c++
不怕犯错,就怕不做9 小时前
git prune 自动删除本地记录中那些远程已经不存在的分支引用
linux·服务器·git
richdata10 小时前
商品数字化不是先做大数据,而是先把数据变成可用决策
大数据·运维·数据治理·商品数字化·智能补货·ai商品决策
weixin_4166679610 小时前
【无标题】
运维·服务器·网络
一池秋_11 小时前
arm低配linux设备,桌面应用冷启动提速方法
linux·运维·arm开发
惜离殇11 小时前
从零开始的敲代码生活--Linux应用软件(文件操作基础1)
linux·c语言·文件操作·标准io