当前位置 博文首页 > wanggao的专栏:muduo学习笔记:net部分之Http--HttpRequest、Ht
前文【muduo学习笔记:net部分之Http-协议简介】简单介绍了HTTP的协议,本文使用muduo网络库简单实现HTTP的请求体和响应体。
客户端发送请求,通过muduo库之后服务端收到的数据存放于Buffer
中,之后解析成HttpRequest
请求对象,再创建一个HttpResponse
响应对象并格式化成Buffer
返回给客户端。服务端解析客户端请求的Buffer使用HttpContext
类。
发送端构造一个HttpRequest,调用成员函数设置请求头、请求体等。调用成员函数请求头字段,使用 const char* start
, const char* end
来传递一个字符串。主要是因为基于TCP的请求数据都保存在Buffer
中,通过解析Buffer中数据进行传递HTTP报文信息。
class HttpRequest : public muduo::copyable
{
public:
enum Method { kInvalid, kGet, kPost, kHead, kPut, kDelete }; //设计支持的请求类型
enum Version { kUnknown, kHttp10, kHttp11 }; // HTTP版本
HttpRequest() : method_(kInvalid), version_(kUnknown) {} //默认构造函数
void setVersion(Version v) { version_ = v; } // 版本
Version getVersion() const { return version_; }
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
void setPath(const char* start, const char* end) { path_.assign(start, end); }
const string& path() const { return path_; }
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_; }
// 请求头的添加键值对
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);
}
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_; }
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_; // 请求行 - URL
string query_; // 请求体
Timestamp receiveTime_; // 请求事件
std::map<string, string> headers_; // 请求头部
};
添加请求头键值对的字符串中,冒号前不能有空格,例如"key:value"或"key: value"是正确的,"key :value"就是错误的。
请求行中的URL中可能带有请求参数,以问号"?"分割,后面的请求参数使用键值对方式,并作为请求体保存。
主要用于构造一个HttpResponse,调用成员函数设置响应头部、响应体,调用appendToBuffer()
格式化到Buffer中,回复给客户端。
class HttpResponse : public muduo::copyable
{
public:
enum HttpStatusCode{
kUnknown,
k200Ok = 200, // 正常
k301MovedPermanently = 301, // 资源不可访问,重定向
k400BadRequest = 400, // 请求错误(域名不存在、请求不正确)
k404NotFound = 404, // 通常是URL不正确(或者因为服务不再提供)
};
explicit HttpResponse(bool close) : statusCode_(kUnknown), closeConnection_(close){}
void setStatusCode(HttpStatusCode code) { statusCode_ = code; }
void setStatusMessage(const string& message) { statusMessage_ = message; }
void setCloseConnection(bool on) { closeConnection_ = on; }
bool closeConnection() const { return closeConnection_; }
void setContentType(const string& contentType) { addHeader("Content-Type", contentType); }
// FIXME: replace string with StringPiece
void addHeader(const string& key, const string& value) { headers_[key] = value; }
void setBody(const string& body) { body_ = body; }
void appendToBuffer(Buffer* output) const; // 将整个HttpRespose对象按照协议输出到Buffer中
private:
std::map<string, string> headers_; // 响应头部,键值对
HttpStatusCode statusCode_; // 响应行 - 状态码
// FIXME: add http version
string statusMessage_; // 响应行 - 状态码文字描述
bool closeConnection_; // 是否关闭连接
string body_; // 响应体
};
函数HttpResponse::appendToBuffer(Buffer* output)
默认使用HTTP1.1版本,按照HTTP协议对HttpResponse对象进行格式化输出到Buffer中。
void HttpResponse::appendToBuffer(Buffer* output) const
{
char buf[32];
// 响应行
snprintf(buf, sizeof buf, "HTTP/1.1 %d ", statusCode_);
output->append(buf)