秋雨De blog

  • 首页
  • 留言板
  • 关于
  • rss
秋雨De blog
一个技术小白的个人博客
  1. 首页
  2. 未分类
  3. 正文

《手写 C++ Web 服务器》:业务逻辑、Cookie 与 Session 管理

2026年3月12日 103点热度 0人点赞 0条评论

在上一篇文章中,我们搭建了 C++ Web 服务器的基础骨架,包括 TCP 监听、异步 Session 管理、HTTP 请求解析以及简单响应发送。这些是服务器的基础能力,但真正的 Web 服务并不仅仅是“接收请求-返回响应”。一个成熟的服务器必须能够:

  1. 处理复杂业务逻辑
  2. 管理用户状态(如登录、购物车等)
  3. 保证请求可追踪性和安全性
  4. 支持多种内容类型和请求体格式

本篇文章将详细介绍我在开源项目 asio_web_service 中实现的 业务逻辑处理、Cookie 与 Session 管理机制,让服务器能够支持真实 Web 应用的功能。


一、业务逻辑框架设计

为了让服务器能够处理多样化业务请求,我设计了一个 集中式业务逻辑管理框架:

std::map<HttpMethod, std::map<std::string, FunctionPtr>> business_logic::function_map = {
    {HttpMethod::GET, {}},
    {HttpMethod::POST, {}},
    ...
};

这里使用了 静态映射表,根据 HTTP 方法(GET、POST 等)和 URI 路径映射到对应的处理函数。

1. 为什么用静态映射表?

  • 可扩展性:新增业务逻辑时,只需要注册一个函数,而不改核心框架
  • 解耦核心和业务:服务器核心只负责网络和 IO,业务逻辑完全独立
  • 统一调度:请求到来时只需根据方法和 URI 查表即可执行对应函数,效率高

注册业务逻辑非常简单,例如:

business_logic::register_handle(HttpMethod::GET, "/hello", [](const http_request_struct &req
{
    return http_response_struct("Hello World", ContentType::TEXT_PLAIN);
});

这行代码就完成了一个 /hello GET 请求的业务处理函数注册。


二、Session 管理与 Cookie

1. Session 的概念

Web 是无状态协议,每次 HTTP 请求都是独立的。为了跟踪用户状态,我们必须在服务器端维护一个 Session。

在 business_logic 中,我使用:

std::map<std::string, std::map<std::string, std::string >> business_logic::session_map;
  • key:session_id(UUID 字符串)
  • value:用户数据映射,如登录状态、临时信息等

2. 创建 Session

当客户端首次访问服务器时,如果没有携带 session Cookie,服务器会创建新的 Session:

std::string business_logic::create_session_map() {
    boost::uuids::uuid uuid = boost::uuids::random_generator()();
    std::string uuidStr = boost::uuids::to_string(uuid);
    session_map[uuidStr] = {}; // 初始化空的 session 数据
    return uuidStr;
}

这里使用 Boost UUID 保证每个 Session 唯一,防止冲突。新 Session 会在响应中通过 Set-Cookie 返回给客户端,客户端保存 Cookie 后,下次请求即可带上 Session ID。

3. 获取 Session

如果客户端请求中已经带了 Cookie,服务器直接使用对应 Session:

if (cookie_map.find("session") == cookie_map.end()) {
    session_id = business_logic::create_session_map();
} else {
    session_id = cookie_map["session"];
}

这样,每个客户端的请求都能访问自己独立的 Session 数据,确保状态隔离。


三、Cookie 的处理

1. 解析客户端 Cookie

HTTP 请求头中包含 Cookie,我们需要解析并存储到映射表:

auto header_cookie = headers.find("Cookie");
if (header_cookie != headers.end()) {
    std::vector<string> cookie_vec;
    boost::split(cookie_vec, header_cookie->second, boost::is_any_of(";"));
    for (const auto &item : cookie_vec) {
        std::vector<string> cookie;
        boost::split(cookie, item, boost::is_any_of("="));
        cookie_map[cookie[0]] = cookie[1];
    }
}
  • 支持多 Cookie
  • 每个 Cookie 会被拆解为 key-value,并存入 cookie_map

2. 设置 Cookie

如果服务器生成了新的 Session,需要在响应中设置 Set-Cookie:

if (self->request.cookie.find("session") == cookie_map.end()) {
    self->response.cookie["session"] = session_id;
}

然后在写入 HTTP 响应时拼接:

if (!cookie.empty()) {
    std::ostringstream oss;
    for (const auto &item: cookie) {
        oss << item.first << "=" << item.second << ";";
    }
    oss.str().pop_back(); // 去掉最后的分号
    headers["Set-Cookie"] = oss.str();
}

浏览器收到后自动存储 Cookie,下一次请求时带上,服务器即可识别用户身份。


四、请求体解析与业务处理

1. 根据 Content-Type 解析请求体

不同业务可能发送 JSON、XML 或表单数据。Session 在接收请求后,会根据 Content-Type 自动解析:

switch (contentType) {
    case ContentType::APPLICATION_JSON:
        boost::property_tree::read_json(stringstream, self->request.ptree);
        break;
    case ContentType::APPLICATION_XML:
        boost::property_tree::read_xml(stringstream, self->request.ptree);
        break;
}

2. 支持 multipart/form-data

对于文件上传或复杂表单数据,解析逻辑如下:

self->request.form_data[field_name] = value;

这样,无论是文本字段还是文件字段,都能被统一存储在 form_data 映射中,业务函数直接读取即可。

3. 调用业务函数

解析完请求参数和内容后,交给 business_logic 统一处理:

self->response = business_logic::process_request(self->request);
  • 如果 URI 对应函数存在,直接调用
  • 否则尝试返回静态文件(GET 请求)
  • 不存在则返回 404

五、写响应与 Cookie 返回

在 Session::do_write() 中:

  1. 构建响应头
  2. 拼接 Set-Cookie
  3. 写入客户端
boost::asio::async_write(client_socket_, boost::asio::buffer(response_str),
    [self = shared_from_this()](std::error_code ec, std::size_t length) {
        if (!ec) {
        } else {
            std::cerr << "write to remote server error: " << ec.message() << std::endl;
        }
    });

异步写入保证了高并发性能。


六、设计哲学与总结

  1. 解耦:业务逻辑完全与核心框架隔离
  2. 可扩展:添加新路由或业务逻辑无需修改底层网络代码
  3. 状态管理:Session + Cookie 实现跨请求用户状态
  4. 统一接口:GET、POST、HEAD 等请求都可统一处理
  5. 多内容支持:JSON、XML、表单数据、文件上传

这一套机制保证了服务器不仅能处理静态请求,也能承载动态 Web 应用。

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: 暂无
最后更新:2026年3月12日

fallrain

种一棵树最好的时间是十年前,其次是现在。

点赞
< 上一篇

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

fallrain

种一棵树最好的时间是十年前,其次是现在。

文章目录
  • 一、业务逻辑框架设计
    • 1. 为什么用静态映射表?
  • 二、Session 管理与 Cookie
    • 1. Session 的概念
    • 2. 创建 Session
    • 3. 获取 Session
  • 三、Cookie 的处理
    • 1. 解析客户端 Cookie
    • 2. 设置 Cookie
  • 四、请求体解析与业务处理
    • 1. 根据 Content-Type 解析请求体
    • 2. 支持 multipart/form-data
    • 3. 调用业务函数
  • 五、写响应与 Cookie 返回
  • 六、设计哲学与总结
友情连接
猫饭范文泉博客迎風别葉CODING手艺人ScarSu博友圈
归档
  • 2026 年 3 月
  • 2025 年 11 月
  • 2025 年 5 月
  • 2025 年 4 月
  • 2025 年 3 月
  • 2024 年 12 月
  • 2024 年 10 月
  • 2024 年 5 月
  • 2023 年 2 月
  • 2022 年 11 月
  • 2022 年 3 月
  • 2021 年 12 月
  • 2021 年 8 月
  • 2021 年 5 月
  • 2021 年 4 月
  • 2021 年 3 月
  • 2020 年 12 月
  • 2020 年 11 月
  • 2020 年 8 月
  • 2020 年 5 月
  • 2019 年 12 月
  • 2019 年 3 月

吉ICP备18007356号

吉公网安备22020302000184号

Theme Kratos Made By Seaton Jiang

COPYRIGHT © 2026 秋雨De blog ALL RIGHTS RESERVED