解析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 发送给浏览器
相关推荐
AlbertS13 小时前
distcc + ccache 编译递归问题排查总结
c++·cmake·gcc·g++·distcc·ccache
小苗卷不动13 小时前
ps axj | grep 和 which命令
c++
云泽80813 小时前
第十五届蓝桥杯大赛软件赛省赛C/C++大学B组
c语言·c++·算法·蓝桥杯
Wadli13 小时前
集群C++聊天服务器
服务器·开发语言·c++
洛水水13 小时前
# 线程池详解:从原理到实现
c++·线程池
思麟呀14 小时前
HTTP的Cookie和Session
linux·网络·c++·网络协议·http
小明同学0114 小时前
linux进程(下)
linux·服务器·c++
汉克老师14 小时前
GESP2023年12月认证C++三级( 第一部分选择题(1-8))
c++·string·字符数组·gesp三级·gesp3级
俺不要写代码14 小时前
lambda表达式理解
c++·算法
澈20714 小时前
动态内存管理:从基础到实战详解
c++·算法