解析muduo源码之 HttpRequest.h

目录

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

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

[2. 核心枚举(HTTP 方法 + 版本)](#2. 核心枚举(HTTP 方法 + 版本))

[3. 私有成员(全部 HTTP 请求内容)](#3. 私有成员(全部 HTTP 请求内容))

[4. 核心功能函数](#4. 核心功能函数)

[1. 设置请求方法](#1. 设置请求方法)

[2. 设置路径 & 查询参数](#2. 设置路径 & 查询参数)

[3. 添加请求头](#3. 添加请求头)

[4. 获取请求头](#4. 获取请求头)

[5. 交换数据](#5. 交换数据)

[5. HTTP 请求解析后长这样](#5. HTTP 请求解析后长这样)

[6. 这个类的作用](#6. 这个类的作用)


一、 HttpRequest.h

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

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

// 作者:陈硕 (chenshuo at chenshuo dot com)
//
// 这是公共头文件,只能包含公共头文件

#ifndef MUDUO_NET_HTTP_HTTPREQUEST_H
#define MUDUO_NET_HTTP_HTTPREQUEST_H

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

#include <map>
#include <assert.h>
#include <stdio.h>

namespace muduo
{
namespace net
{

/// HTTP 请求对象:封装一次 HTTP 请求的所有信息
/// 可拷贝,用于存储解析后的请求行、请求头、路径、参数等
class HttpRequest : public muduo::copyable
{
 public:
  /// HTTP 请求方法枚举
  enum Method
  {
    kInvalid,  // 无效方法
    kGet,      // GET
    kPost,     // POST
    kHead,     // HEAD
    kPut,      // PUT
    kDelete    // DELETE
  };

  /// HTTP 版本枚举
  enum Version
  {
    kUnknown,  // 未知版本
    kHttp10,   // HTTP/1.0
    kHttp11    // HTTP/1.1
  };

  /// 构造函数:初始化为无效方法、未知版本
  HttpRequest()
    : method_(kInvalid),
      version_(kUnknown)
  {
  }

  /// 设置 HTTP 版本
  void setVersion(Version v)
  {
    version_ = v;
  }

  /// 获取 HTTP 版本
  Version getVersion() const
  { return version_; }

  /// 设置 HTTP 请求方法(从字符串解析)
  /// @param start 方法字符串起始
  /// @param end 方法字符串结束
  bool setMethod(const char* start, const char* end)
  {
    assert(method_ == kInvalid);
    string m(start, end);
    if (m == "GET")
    {
      method_ = kGet;
    }
    else if (m == "POST")
    {
      method_ = kPost;
    }
    else if (m == "HEAD")
    {
      method_ = kHead;
    }
    else if (m == "PUT")
    {
      method_ = kPut;
    }
    else if (m == "DELETE")
    {
      method_ = kDelete;
    }
    else
    {
      method_ = kInvalid;
    }
    return method_ != kInvalid;
  }

  /// 获取请求方法(枚举)
  Method method() const
  { return method_; }

  /// 获取请求方法(字符串形式,用于日志/输出)
  const char* methodString() const
  {
    const char* result = "UNKNOWN";
    switch(method_)
    {
      case kGet:
        result = "GET";
        break;
      case kPost:
        result = "POST";
        break;
      case kHead:
        result = "HEAD";
        break;
      case kPut:
        result = "PUT";
        break;
      case kDelete:
        result = "DELETE";
        break;
      default:
        break;
    }
    return result;
  }

  /// 设置请求路径(URL 中的 path 部分)
  void setPath(const char* start, const char* end)
  {
    path_.assign(start, end);
  }

  /// 获取请求路径
  const string& path() const
  { return path_; }

  /// 设置请求参数(URL ? 后面的 query string)
  void setQuery(const char* start, const char* end)
  {
    query_.assign(start, end);
  }

  /// 获取请求参数
  const string& query() const
  { return query_; }

  /// 设置请求接收时间戳
  void setReceiveTime(Timestamp t)
  { receiveTime_ = t; }

  /// 获取请求接收时间
  Timestamp receiveTime() const
  { return receiveTime_; }

  /// 添加一个 HTTP 请求头
  /// @param start 头字段起始
  /// @param colon 冒号位置
  /// @param end 头字段结束
  void addHeader(const char* start, const char* colon, const char* end)
  {
    // 提取字段名
    string field(start, colon);
    ++colon;

    // 跳过冒号后的空白字符
    while (colon < end && isspace(*colon))
    {
      ++colon;
    }

    // 提取字段值
    string value(colon, end);

    // 去掉值末尾的空白字符
    while (!value.empty() && isspace(value[value.size()-1]))
    {
      value.resize(value.size()-1);
    }

    // 存入请求头map
    headers_[field] = value;
  }

  /// 根据字段名获取请求头值
  string getHeader(const string& field) const
  {
    string result;
    std::map<string, string>::const_iterator it = headers_.find(field);
    if (it != headers_.end())
    {
      result = it->second;
    }
    return result;
  }

  /// 获取所有请求头
  const std::map<string, string>& headers() const
  { return headers_; }

  /// 交换两个 HttpRequest 对象(高效)
  void swap(HttpRequest& that)
  {
    std::swap(method_, that.method_);
    std::swap(version_, that.version_);
    path_.swap(that.path_);
    query_.swap(that.query_);
    receiveTime_.swap(that.receiveTime_);
    headers_.swap(that.headers_);
  }

 private:
  Method method_;               // 请求方法
  Version version_;             // HTTP 版本
  string path_;                 // 请求路径
  string query_;                // 请求参数
  Timestamp receiveTime_;       // 请求接收时间
  std::map<string, string> headers_;  // 请求头集合
};

}  // namespace net
}  // namespace muduo

#endif  // MUDUO_NET_HTTP_HTTPREQUEST_H

1. 整体定位

HttpRequest = 一条 HTTP 请求的 "容器"

它把 HTTP 请求报文全部解析成 C++ 对象:

  • 请求方法(GET/POST...)
  • URL 路径(/index.html)
  • 查询参数(?id=1)
  • HTTP 版本(1.0 / 1.1)
  • 请求头(headers)
  • 接收时间

它只存数据,不做网络 IO。

2. 核心枚举(HTTP 方法 + 版本)

cpp 复制代码
enum Method {
  kInvalid,
  kGet,    // GET
  kPost,   // POST
  kHead,
  kPut,
  kDelete
};

enum Version {
  kUnknown,
  kHttp10, // HTTP/1.0
  kHttp11  // HTTP/1.1
};

3. 私有成员(全部 HTTP 请求内容)

cpp 复制代码
Method method_;          // 请求方法
Version version_;        // 版本
string path_;            // 路径 /index
string query_;           // 查询参数 ?id=1
Timestamp receiveTime_;  // 接收时间
map<string, string> headers_; // 请求头

4. 核心功能函数

1. 设置请求方法
cpp 复制代码
bool setMethod(const char* start, const char* end);

把字符串 "GET" → 转成枚举 kGet

2. 设置路径 & 查询参数
cpp 复制代码
void setPath(const char* start, const char* end);
void setQuery(const char* start, const char* end);
3. 添加请求头
cpp 复制代码
void addHeader(const char* start, const char* colon, const char* end);

解析:

cpp 复制代码
Host: www.baidu.com

存入 map

cpp 复制代码
headers_["Host"] = "www.baidu.com"
4. 获取请求头
cpp 复制代码
string getHeader(const string& field) const;
5. 交换数据
cpp 复制代码
void swap(HttpRequest& that);

内部字符串、map 直接交换,不拷贝,非常高效。

5. HTTP 请求解析后长这样

cpp 复制代码
GET /index?name=foo HTTP/1.1\r\n
Host: example.com\r\n
Connection: keep-alive\r\n
\r\n

解析后存入 HttpRequest:

cpp 复制代码
method_ = kGet
path_ = "/index"
query_ = "name=foo"
version_ = kHttp11
headers_["Host"] = "example.com"
headers_["Connection"] = "keep-alive"

6. 这个类的作用

  • HttpServer 解析 HTTP 请求后,放进 HttpRequest
  • 交给用户回调函数
  • 用户从里面取:
    • 路径
    • 方法
    • 参数
    • 请求头
  • 用户再通过 HttpResponse 构造返回报文
相关推荐
2401_879693871 小时前
C++中的代理模式高级应用
开发语言·c++·算法
王璐WL1 小时前
【c++】隐藏的this指针
c++
2501_924952692 小时前
C++中的枚举类高级用法
开发语言·c++·算法
2401_873204652 小时前
代码覆盖率工具实战
开发语言·c++·算法
少司府2 小时前
C++基础入门:第一个C++程序
java·c语言·开发语言·c++·ide
不染尘.2 小时前
欧拉路径算法
开发语言·数据结构·c++·算法·图论
️是782 小时前
信息奥赛一本通—编程启蒙(3345:【例60.2】 约瑟夫问题)
开发语言·c++·算法
add45a2 小时前
C++中的智能指针详解
开发语言·c++·算法
王璐WL2 小时前
【C++】string类扩展知识
c++