这个模块是 HTTP 请求数据模块,用于存储 HTTP 的请求信息,然后按照 HTTP 请求格式进行解析,得到各个关键要素放到 Request 中,这样子能让 HTTP 请求的分析更加的方便!
其中成员变量,也就是要分析的内容无非就是请求报文中的要素,这些成员变量我们将其设为公有属性,便于外界的直接访问,如下所示:
- 请求方法
URL:- 资源路径
- 查询字符串(用哈希表存储各个键值对,方便查找)
- 协议版本
- 头部字段(用哈希表存储各个键值对,方便查找)
- 正文
- 此外我们还需要一个
std::smatch成员变量,用来保存通过使用正则表达式进行解析后得到的数据。(比如资源路径中的数字等等……)

所以需要提供以下接口:
- 提供对查询字符串、头部字段的的插入和获取功能
- 长连接和短连接的判断
- 获取正文长度
class HttpRequest
{
public:
std::string _method; // 请求方法
std::string _path; // 资源路径
std::unordered_map<std::string, std::string> _queryString; // 查询字符串
std::string _version; // 协议版本
std::unordered_map<std::string, std::string> _header; // 头部字段
std::string _body; // 请求正文
std::smatch _matches; // 资源路径的正则提取数据
public:
HttpRequest();
// 插入头部字段
void set_header(const std::string& key, const std::string& val);
// 判断是否存在指定头部字段
bool has_header(const std::string& key) const;
// 获取指定头部字段的值
std::string get_header_val(const std::string& key) const;
// 插入查询字符串
void set_queryString(const std::string& key, const std::string& val);
// 判断是否存在指定查询字符串
bool has_queryString(const std::string& key) const;
// 获取指定查询字符串的值
std::string get_queryString_val(const std::string& key) const;
// 获取正文长度
size_t get_body_length() const;
// 判断是否为短连接
bool is_short_connection() const;
// 成员变量清理接口
void reset();
};Ⅱ. 接口实现
接口并不难,这里就不细讲了,直接参考注释即可!
class HttpRequest
{
public:
std::string _method; // 请求方法
std::string _path; // 资源路径
std::unordered_map<std::string, std::string> _queryString; // 查询字符串
std::string _version; // 协议版本
std::unordered_map<std::string, std::string> _header; // 头部字段
std::string _body; // 请求正文
std::smatch _matches; // 资源路径的正则提取数据
public:
HttpRequest()
: _version("HTTP/1.1")
{}
// 插入头部字段
void set_header(const std::string& key, const std::string& val) { _header[key] = val; }
// 判断是否存在指定头部字段
bool has_header(const std::string& key) const
{
auto it = _header.find(key);
if(it == _header.end())
return false;
return true;
}
// 获取指定头部字段的值
std::string get_header_val(const std::string& key) const
{
auto it = _header.find(key);
if(it == _header.end())
return "";
return it->second;
}
// 插入查询字符串
void set_queryString(const std::string& key, const std::string& val) { _queryString[key] = val; }
// 判断是否存在指定查询字符串
bool has_queryString(const std::string& key) const
{
auto it = _queryString.find(key);
if(it == _queryString.end())
return false;
return true;
}
// 获取指定查询字符串的值
std::string get_queryString_val(const std::string& key) const
{
auto it = _queryString.find(key);
if(it == _queryString.end())
return "";
return it->second;
}
// 获取正文长度
size_t get_body_length() const
{
// 通过头部字段中的Content-Length来获取,比如Content-Length: 1024\r\n
bool ret = has_header("Content-Length");
if(ret == false)
return 0;
return std::stol(get_header_val("Content-Length"));
}
// 判断是否为短连接
bool is_short_connection() const
{
// 通过头部字段中的Connection来判断,如果是close表示短连接,keep-alive表示长连接
bool ret = has_header("Connection");
if(ret == false)
return false;
return get_header_val("Connection") == "close";
}
public:
// 成员变量清理接口
void reset()
{
_method.clear();
_path.clear();
_queryString.clear();
_version = "HTTP/1.1"; // 注意这里版本号不能清空,因为有地方可能会清理完之后还用到它,为空的话会导致内存错误
_header.clear();
_body.clear();
// smatch比较特殊,它没有clear()接口,所以我们可以用一个空的smatch与其进行交换达到清空的效果
std::smatch tmp;
_matches.swap(tmp);
}
};