目录
[一、 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 构造返回报文