解析muduo源码之 HttpResponse.h & HttpResponse.cc

目录

[一、 HttpResponse.h](#一、 HttpResponse.h)

[1. 整体定位](#1. 整体定位)

[2. 核心结构](#2. 核心结构)

[1. 状态码 + 状态描述](#1. 状态码 + 状态描述)

[2. 响应头 headers_](#2. 响应头 headers_)

[3. 是否关闭连接 closeConnection_](#3. 是否关闭连接 closeConnection_)

[4. 响应体 body_](#4. 响应体 body_)

[3. 核心函数:appendToBuffer ()](#3. 核心函数:appendToBuffer ())

[4. 典型使用流程](#4. 典型使用流程)

[5. 和 HttpRequest 的关系](#5. 和 HttpRequest 的关系)

[二、 HttpResponse.cc](#二、 HttpResponse.cc)

[1. 核心功能一句话](#1. 核心功能一句话)

[2. 逐段拆解](#2. 逐段拆解)

[1. 拼接【状态行】](#1. 拼接【状态行】)

[2. 拼接【Connection + Content-Length】](#2. 拼接【Connection + Content-Length】)

[3. 拼接【所有响应头】](#3. 拼接【所有响应头】)

[4. 头部结束,加空行](#4. 头部结束,加空行)

[5. 最后加【响应体】](#5. 最后加【响应体】)

[3. 最终组装出来的 HTTP 报文长这样](#3. 最终组装出来的 HTTP 报文长这样)

[4. 这个类在 HTTP 服务中的位置](#4. 这个类在 HTTP 服务中的位置)


一、 HttpResponse.h

先贴出完整代码,再逐部分解释:

cpp 复制代码
// Copyright 2010, Shuo Chen. 保留所有权利。
// http://code.google.com/p/muduo/
//
// 本源代码的使用受 BSD 许可证约束
// 可在 License 文件中找到许可证条款。

// 作者:陈硕 (chenshuo at chenshuo dot com)
//
// 这是一个公共头文件,仅允许包含其他公共头文件。

#ifndef MUDUO_NET_HTTP_HTTPRESPONSE_H
#define MUDUO_NET_HTTP_HTTPRESPONSE_H

#include "muduo/base/copyable.h"
#include "muduo/base/Types.h"

#include <map>

namespace muduo
{
namespace net
{

class Buffer;

///
/// HTTP 响应对象
/// 用于构造 HTTP 响应报文(状态行、响应头、响应体),并最终序列化到 Buffer 发送
///
class HttpResponse : public muduo::copyable
{
 public:
  /// HTTP 状态码枚举
  enum HttpStatusCode
  {
    kUnknown,             // 未知状态码
    k200Ok = 200,          // 成功
    k301MovedPermanently = 301, // 永久重定向
    k400BadRequest = 400,  // 错误请求
    k404NotFound = 404,    // 资源未找到
  };

  /// 构造函数
  /// @param close 是否在响应发送完毕后关闭连接(Connection: close)
  explicit HttpResponse(bool close)
    : statusCode_(kUnknown),
      closeConnection_(close)
  {
  }

  /// 设置 HTTP 状态码
  void setStatusCode(HttpStatusCode code)
  { statusCode_ = code; }

  /// 设置 HTTP 状态消息(如 "OK" / "Not Found")
  void setStatusMessage(const string& message)
  { statusMessage_ = message; }

  /// 设置是否关闭连接
  void setCloseConnection(bool on)
  { closeConnection_ = on; }

  /// 判断是否关闭连接
  bool closeConnection() const
  { return closeConnection_; }

  /// 设置响应体类型(Content-Type)
  void setContentType(const string& contentType)
  { addHeader("Content-Type", contentType); }

  /// 添加一个 HTTP 响应头
  /// FIXME: 后续可用 StringPiece 替代 string 提升效率
  void addHeader(const string& key, const string& value)
  { headers_[key] = value; }

  /// 设置响应体内容
  void setBody(const string& body)
  { body_ = body; }

  /// 将完整的 HTTP 响应报文追加到输出缓冲区(用于发送)
  void appendToBuffer(Buffer* output) const;

 private:
  std::map<string, string> headers_;     // 响应头集合
  HttpStatusCode statusCode_;             // 状态码
  string statusMessage_;                 // 状态消息
  bool closeConnection_;                  // 是否关闭连接
  string body_;                           // 响应体
};

}  // namespace net
}  // namespace muduo

#endif  // MUDUO_NET_HTTP_HTTPRESPONSE_H

1. 整体定位

HttpResponse = 构造 HTTP 响应报文的工具

  • 用户设置:状态码、响应头、响应体
  • 它负责:拼接成标准 HTTP 响应格式
  • 写入 Buffer → 发送给浏览器

2. 核心结构

cpp 复制代码
class HttpResponse : public copyable
{
public:
  // 状态码
  enum HttpStatusCode {
    kUnknown,
    k200Ok = 200,
    k301MovedPermanently = 301,
    k400BadRequest = 400,
    k404NotFound = 404
  };

  // 设置
  void setStatusCode(HttpStatusCode code);
  void setStatusMessage(const string& message);
  void setCloseConnection(bool on);
  void setContentType(const string& contentType);
  void addHeader(const string& key, const string& value);
  void setBody(const string& body);

  // 序列化成Buffer(发送给客户端)
  void appendToBuffer(Buffer* output) const;

private:
  std::map<string, string> headers_;
  HttpStatusCode statusCode_;
  string statusMessage_;
  bool closeConnection_;
  string body_;
};
1. 状态码 + 状态描述
cpp 复制代码
HttpStatusCode statusCode_;
string statusMessage_;

对应 HTTP 首行:

cpp 复制代码
HTTP/1.1 200 OK
2. 响应头 headers_
cpp 复制代码
map<string, string> headers_;

对应:

cpp 复制代码
Content-Type: text/html
Connection: keep-alive
3. 是否关闭连接 closeConnection_
  • true:回复后立刻断开(Connection: close
  • false:长连接(Connection: Keep-Alive
4. 响应体 body_

网页内容、JSON、HTML 等。

3. 核心函数:appendToBuffer ()

把 HttpResponse 序列化成真实 HTTP 响应报文,写入 Buffer 发送。

拼接格式:

cpp 复制代码
HTTP/1.1 200 OK\r\n
Content-Type: text/html\r\n
Connection: Keep-Alive\r\n
\r\n
<html>...网页内容...</html>

这就是浏览器能识别的原始 HTTP 响应

4. 典型使用流程

cpp 复制代码
// 用户收到 HttpRequest 后,构造 HttpResponse
HttpResponse response(false); // 长连接

response.setStatusCode(HttpResponse::k200Ok);
response.setStatusMessage("OK");
response.setContentType("text/html");
response.setBody("<h1>Hello World</h1>");

// 序列化 → 发送
response.appendToBuffer(outputBuf);
conn->send(outputBuf);

5. 和 HttpRequest 的关系

cpp 复制代码
浏览器发送 → HttpRequest(解析后)
用户处理    → 生成 HttpResponse
回复浏览器  ← HttpResponse(序列化后)

二、 HttpResponse.cc

先贴出完整代码,再逐部分解释:

cpp 复制代码
// Copyright 2010, Shuo Chen. 保留所有权利。
// http://code.google.com/p/muduo/
//
// 本源代码的使用受 BSD 许可证约束
// 可在 License 文件中找到许可证条款。

// 作者:陈硕 (chenshuo at chenshuo dot com)

#include "muduo/net/http/HttpResponse.h"
#include "muduo/net/Buffer.h"

#include <stdio.h>

using namespace muduo;
using namespace muduo::net;

/// 将 HTTP 响应组装成标准协议格式,写入输出缓冲区
void HttpResponse::appendToBuffer(Buffer* output) const
{
  char buf[32];

  /// 1. 组装状态行:HTTP/1.1 200 OK\r\n
  snprintf(buf, sizeof buf, "HTTP/1.1 %d ", statusCode_);
  output->append(buf);
  output->append(statusMessage_);
  output->append("\r\n");

  /// 2. 处理连接头与长度头
  if (closeConnection_)
  {
    // 短连接:发送完直接关闭
    output->append("Connection: close\r\n");
  }
  else
  {
    // 长连接:必须带上 Content-Length
    snprintf(buf, sizeof buf, "Content-Length: %zd\r\n", body_.size());
    output->append(buf);
    output->append("Connection: Keep-Alive\r\n");
  }

  /// 3. 追加所有响应头
  for (const auto& header : headers_)
  {
    output->append(header.first);
    output->append(": ");
    output->append(header.second);
    output->append("\r\n");
  }

  /// 4. 空行分隔头部与body
  output->append("\r\n");
  /// 5. 追加响应体
  output->append(body_);
}

1. 核心功能一句话

cpp 复制代码
void HttpResponse::appendToBuffer(Buffer* output) const

把响应状态行 + 响应头 + 空行 + 响应体 → 拼接到 Buffer 里发给客户端。

2. 逐段拆解

1. 拼接【状态行】
cpp 复制代码
snprintf(buf, sizeof buf, "HTTP/1.1 %d ", statusCode_);
output->append(buf);
output->append(statusMessage_);
output->append("\r\n");

生成:

cpp 复制代码
HTTP/1.1 200 OK\r\n
  • 固定使用 HTTP/1.1
  • statusCode_ → 200/404/301
  • statusMessage_ → OK / Not Found
2. 拼接【Connection + Content-Length】
cpp 复制代码
if (closeConnection_)
{
  output->append("Connection: close\r\n");
}
else
{
  snprintf(buf, sizeof buf, "Content-Length: %zd\r\n", body_.size());
  output->append(buf);
  output->append("Connection: Keep-Alive\r\n");
}

规则:

  • 长连接(Keep-Alive)必须带 Content-Length浏览器才知道 body 何时结束
  • 短连接(close)不需要 Content-Length断开连接即结束
3. 拼接【所有响应头】
cpp 复制代码
for (const auto& header : headers_)
{
  output->append(header.first);
  output->append(": ");
  output->append(header.second);
  output->append("\r\n");
}

例如:

cpp 复制代码
Content-Type: text/html\r\n
Server: muduo\r\n
4. 头部结束,加空行
cpp 复制代码
output->append("\r\n");

HTTP 规定:头部与 body 之间必须空一行

5. 最后加【响应体】
cpp 复制代码
output->append(body_);

如:<h1>Hello</h1>{"key":"value"}

3. 最终组装出来的 HTTP 报文长这样

cpp 复制代码
HTTP/1.1 200 OK\r\n
Content-Length: 5\r\n
Connection: Keep-Alive\r\n
Content-Type: text/html\r\n
\r\n
hello

4. 这个类在 HTTP 服务中的位置

cpp 复制代码
HttpRequest  :: 解析浏览器请求
          ↓
用户业务逻辑处理
          ↓
HttpResponse :: 构造响应
          ↓
appendToBuffer :: 序列化成原始HTTP报文
          ↓
TcpConnection::send 发送给浏览器
相关推荐
小白学习记录555552 小时前
vs2019无法自动补全QT代码
c++
小糯米6012 小时前
C++ 单调栈原理与模板
开发语言·c++·算法
XZXZZX3 小时前
ATCODER ABC 450 C题解
c++·算法·ccf csp
像素猎人3 小时前
差分数组【自用笔记】【c++】
c++·笔记·算法
kyle~3 小时前
ROS2 Control
c++·嵌入式硬件·机器人·ros2
xiaoye-duck3 小时前
《算法题讲解指南:优选算法-哈希表》--58.存在重复元素I,59.存在重复元素II,60.字母异位词分组
数据结构·c++·哈希算法
hetao17338373 小时前
2026-03-26 ZYZ28-CSP-XiaoMao Round 2 hetao1733837 的 record
c++·算法
火柴-人3 小时前
用 AI 调试渲染 Bug:renderdoc-mcp 进阶工作流
c++·人工智能·图形渲染·claude·codex·mcp·renderdoc
梓䈑3 小时前
【CMake】cmake实现属性传递的秘密(目标的默认输出路径 以及 如何修改输出路径)
c++·cmake