目录
[一、 HttpServer.h](#一、 HttpServer.h)
[1. 一句话定位](#1. 一句话定位)
[2. 类结构](#2. 类结构)
[3. 核心:用户回调](#3. 核心:用户回调)
[4. HttpServer 工作流程](#4. HttpServer 工作流程)
[5. HttpServer 内部组件关系](#5. HttpServer 内部组件关系)
[6. 为什么 HttpServer 如此简单](#6. 为什么 HttpServer 如此简单)
[二、 HttpServer.cc](#二、 HttpServer.cc)
[1. 一句话总结](#1. 一句话总结)
[2. 默认回调](#2. 默认回调)
[3. 构造函数 HttpServer::HttpServer ()](#3. 构造函数 HttpServer::HttpServer ())
[4. 连接建立:onConnection ()](#4. 连接建立:onConnection ())
[5. 消息到达:onMessage ()](#5. 消息到达:onMessage ())
[6. 请求处理:onRequest ()](#6. 请求处理:onRequest ())
[7. HttpServer 工作全流程图](#7. HttpServer 工作全流程图)
[8. HttpServer 最核心的作用](#8. HttpServer 最核心的作用)
一、 HttpServer.h
先贴出完整代码,再逐部分解释:
cpp
// Copyright 2010, Shuo Chen. 保留所有权利。
// http://code.google.com/p/muduo/
//
// 本源代码的使用受 BSD 许可证约束
// 可在 License 文件中找到许可证条款。
// 作者:陈硕 (chenshuo at chenshuo dot com)
//
// 这是公共头文件,只能包含公共头文件。
#ifndef MUDUO_NET_HTTP_HTTPSERVER_H
#define MUDUO_NET_HTTP_HTTPSERVER_H
#include "muduo/net/TcpServer.h"
namespace muduo
{
namespace net
{
class HttpRequest;
class HttpResponse;
///
/// 简单可嵌入式 HTTP 服务器
/// 主要用于程序状态上报
/// 并非完整兼容 HTTP/1.1,但能与浏览器、HTTP 客户端正常通信
/// 同步处理模型,类似 Java Servlet
///
class HttpServer : noncopyable
{
public:
/// HTTP 请求回调函数类型
/// 参数:解析好的请求、用于填写回复的响应对象
typedef std::function<void (const HttpRequest&, HttpResponse*)> HttpCallback;
/// 构造函数
/// @param loop 主事件循环
/// @param listenAddr 监听地址
/// @param name 服务器名称
/// @param option 端口复用选项
HttpServer(EventLoop* loop,
const InetAddress& listenAddr,
const string& name,
TcpServer::Option option = TcpServer::kNoReusePort);
/// 获取事件循环
EventLoop* getLoop() const { return server_.getLoop(); }
/// 设置 HTTP 请求处理回调
/// 非线程安全,必须在 start() 之前注册
void setHttpCallback(const HttpCallback& cb)
{
httpCallback_ = cb;
}
/// 设置 IO 线程池数量
void setThreadNum(int numThreads)
{
server_.setThreadNum(numThreads);
}
/// 启动服务器
void start();
private:
/// TCP 连接建立/断开回调
void onConnection(const TcpConnectionPtr& conn);
/// TCP 消息到达回调(接收数据、解析 HTTP)
void onMessage(const TcpConnectionPtr& conn,
Buffer* buf,
Timestamp receiveTime);
/// HTTP 请求解析完成后回调(处理业务)
void onRequest(const TcpConnectionPtr&, const HttpRequest&);
TcpServer server_; // 底层 TCP 服务器
HttpCallback httpCallback_; // 用户设置的 HTTP 业务回调
};
} // namespace net
} // namespace muduo
#endif // MUDUO_NET_HTTP_HTTPSERVER_H
1. 一句话定位
HttpServer = 基于 TcpServer 封装的 HTTP 专用服务器
- 内部持有一个
TcpServer - 帮你自动处理 HTTP 解析
- 帮你自动处理请求 / 响应
- 给用户提供极简 HTTP 回调接口
- 用户不用关心底层 TCP、粘包、解析,只用写业务
用户只需要关心:收到一个 HttpRequest,回一个 HttpResponse。
2. 类结构
cpp
class HttpServer
{
public:
// 用户回调:输入 HttpRequest,输出 HttpResponse
typedef std::function<void(const HttpRequest&, HttpResponse*)> HttpCallback;
HttpServer(EventLoop* loop, const InetAddress& listenAddr, ...);
void setHttpCallback(HttpCallback cb); // 设置业务回调
void setThreadNum(int numThreads); // 设置线程数
void start(); // 启动服务器
private:
// 内部回调
void onConnection(...); // 连接建立/断开
void onMessage(...); // 消息到达 → 解析 HTTP
void onRequest(...); // 解析完成 → 调用用户回调
TcpServer server_; // 底层 TCP 服务器
HttpCallback httpCallback_;// 用户业务回调
};
3. 核心:用户回调
cpp
typedef std::function<void(
const HttpRequest& req, // 输入:解析好的请求
HttpResponse* resp // 输出:你要构造的响应
)> HttpCallback;
用户代码只需要写这个:
cpp
void onHttpRequest(const HttpRequest& req, HttpResponse* resp)
{
resp->setStatusCode(200);
resp->setBody("Hello World");
}
**这就是全部!**底层 TCP、解析、发送,HttpServer 全部帮你搞定。
4. HttpServer 工作流程
cpp
浏览器发送 HTTP 请求
↓
TcpServer 接收连接
↓
onMessage 收到数据
↓
HttpContext 解析(状态机)
↓
解析完成 → HttpRequest
↓
调用用户回调 httpCallback_
↓
用户填充 HttpResponse
↓
HttpResponse.appendToBuffer
↓
TcpConnection 发送回浏览器
5. HttpServer 内部组件关系
cpp
HttpServer
│
├─ TcpServer(底层网络)
│
├─ 每个连接自带 HttpContext(解析)
│
└─ 给用户提供:HttpRequest → HttpResponse
6. 为什么 HttpServer 如此简单
因为:
- TcpServer 负责网络
- HttpContext 负责解析
- HttpRequest/HttpResponse 负责数据结构
- HttpServer 只负责把它们串起来
这就是模块化的威力!
二、 HttpServer.cc
先贴出完整代码,再逐部分解释:
cpp
// Copyright 2010, Shuo Chen. 保留所有权利。
// http://code.google.com/p/muduo/
//
// 本源代码的使用受 BSD 许可证约束
// 可在 License 文件中找到许可证条款。
// 作者:陈硕 (chenshuo at chenshuo dot com)
#include "muduo/net/http/HttpServer.h"
#include "muduo/base/Logging.h"
#include "muduo/net/http/HttpContext.h"
#include "muduo/net/http/HttpRequest.h"
#include "muduo/net/http/HttpResponse.h"
using namespace muduo;
using namespace muduo::net;
namespace muduo
{
namespace net
{
namespace detail
{
// 默认 HTTP 回调:未找到资源,返回 404
void defaultHttpCallback(const HttpRequest&, HttpResponse* resp)
{
resp->setStatusCode(HttpResponse::k404NotFound);
resp->setStatusMessage("Not Found");
resp->setCloseConnection(true);
}
} // namespace detail
} // namespace net
} // namespace muduo
// 构造函数:初始化底层 TcpServer,设置默认回调
HttpServer::HttpServer(EventLoop* loop,
const InetAddress& listenAddr,
const string& name,
TcpServer::Option option)
: server_(loop, listenAddr, name, option),
httpCallback_(detail::defaultHttpCallback)
{
// 设置 TCP 连接回调
server_.setConnectionCallback(
std::bind(&HttpServer::onConnection, this, _1));
// 设置 TCP 消息回调
server_.setMessageCallback(
std::bind(&HttpServer::onMessage, this, _1, _2, _3));
}
// 启动 HTTP 服务器
void HttpServer::start()
{
LOG_WARN << "HttpServer[" << server_.name()
<< "] starts listening on " << server_.ipPort();
server_.start();
}
// TCP 连接建立/断开时调用
void HttpServer::onConnection(const TcpConnectionPtr& conn)
{
// 连接建立时,为连接绑定一个 HttpContext 上下文(用于解析 HTTP)
if (conn->connected())
{
conn->setContext(HttpContext());
}
}
// TCP 消息到达:接收数据并解析 HTTP 请求
void HttpServer::onMessage(const TcpConnectionPtr& conn,
Buffer* buf,
Timestamp receiveTime)
{
// 从连接上下文取出 HttpContext
HttpContext* context = boost::any_cast<HttpContext>(conn->getMutableContext());
// 解析 HTTP 请求,解析失败返回 400 错误
if (!context->parseRequest(buf, receiveTime))
{
conn->send("HTTP/1.1 400 Bad Request\r\n\r\n");
conn->shutdown();
}
// 如果解析完成一个完整请求
if (context->gotAll())
{
// 交给业务逻辑处理
onRequest(conn, context->request());
// 重置上下文,准备解析下一个请求(长连接)
context->reset();
}
}
// 处理 HTTP 请求:构造响应并发送
void HttpServer::onRequest(const TcpConnectionPtr& conn, const HttpRequest& req)
{
// 根据请求头判断是否需要关闭连接
const string& connection = req.getHeader("Connection");
bool close = connection == "close" ||
(req.getVersion() == HttpRequest::kHttp10 && connection != "Keep-Alive");
// 创建 HTTP 响应对象
HttpResponse response(close);
// 调用用户注册的业务回调
httpCallback_(req, &response);
// 将响应序列化到缓冲区
Buffer buf;
response.appendToBuffer(&buf);
// 发送响应
conn->send(&buf);
// 如果是短连接,发送完毕后关闭
if (response.closeConnection())
{
conn->shutdown();
}
}
1. 一句话总结
HttpServer 不做网络、不做解析,只做 "调度"
- 网络:交给
TcpServer - 解析:交给
HttpContext - 数据:交给
HttpRequest/HttpResponse - 它只负责:收到数据 → 解析 → 调用用户 → 发回响应
2. 默认回调
cpp
void defaultHttpCallback(...)
{
resp->setStatusCode(404);
resp->setStatusMessage("Not Found");
}
作用:访问不存在的页面 → 返回 404
3. 构造函数 HttpServer::HttpServer ()
cpp
HttpServer::HttpServer(...)
: server_(loop, ...), // 内部创建TcpServer
httpCallback_(defaultHttpCallback)
{
// 监听连接建立/断开
server_.setConnectionCallback(&HttpServer::onConnection);
// 监听消息到达
server_.setMessageCallback(&HttpServer::onMessage);
}
作用:把 TcpServer 的事件,全部接管过来自己处理。
4. 连接建立:onConnection ()
cpp
void HttpServer::onConnection(const TcpConnectionPtr& conn)
{
if (conn->connected())
{
// 给这个连接绑定一个 HttpContext(解析器)
conn->setContext(HttpContext());
}
}
关键点:一个 TCP 连接 → 绑定一个 HttpContext 解析器长连接多条请求,复用同一个解析器。
5. 消息到达:onMessage ()
cpp
void HttpServer::onMessage(...)
{
// 取出连接绑定的解析器
HttpContext* context = ...conn->getMutableContext();
// 1. 解析 HTTP 请求
if (!context->parseRequest(buf, receiveTime))
{
// 解析失败 → 400 错误
conn->send("HTTP/1.1 400 Bad Request\r\n\r\n");
conn->shutdown();
}
// 2. 如果解析完成
if (context->gotAll())
{
// 交给用户业务处理
onRequest(conn, context->request());
// 重置解析器,准备下一条请求
context->reset();
}
}
这就是 HTTP 解析的完整流程:
- 从 TCP 连接拿解析器
HttpContext - 把 Buffer 数据交给解析器
- 解析完成 → 调用业务
- 重置解析器 → 长连接继续用
6. 请求处理:onRequest ()
cpp
void HttpServer::onRequest(...)
{
// 判断是否长连接
bool close = ...;
// 创建 HTTP 响应
HttpResponse response(close);
// ------------------------ 调用用户代码 ------------------------
httpCallback_(req, &response);
// 把响应转成 Buffer
Buffer buf;
response.appendToBuffer(&buf);
// 发送给客户端
conn->send(&buf);
// 如果短连接,发送完关闭
if (response.closeConnection())
conn->shutdown();
}
这里做了 4 件事:
- 判断连接是否保持(长连接)
- 创建
HttpResponse - 调用用户回调(你写的业务逻辑)
- 发送响应,关闭或保持连接
7. HttpServer 工作全流程图
cpp
浏览器请求
↓
TcpConnection 收到数据
↓
onMessage()
↓
HttpContext 解析(状态机)
↓
解析完成 → HttpRequest
↓
onRequest()
↓
用户回调:你处理 req → resp
↓
HttpResponse 打包成协议
↓
发送回浏览器
↓
短连接关闭 / 长连接等待下一条
8. HttpServer 最核心的作用
- 封装 TcpServer,提供 HTTP 专用接口
- 自动管理 HttpContext,完成协议解析
- 用户只写业务:HttpRequest → HttpResponse