上文解析HTTP请求报文(GET、POST),介绍了计划实现的WEB服务器的五个功能:展示主页(GET)、用户登录(POST)、用户注册(POST)、获取图片(GET)、获取视频(GET)。

通过正则表达式与状态机解析HTTP请求报文后,就获得了客户端请求资源的路径(path),回送响应报文的过程就是:根据请求写出相应的HTTP响应头,然后再将path上的文件置于响应体,通过socket发往客户端。

首先是制作HTTP响应头:

HTTP/2 200 OK\r\n
last-modified: Sat, 24 Dec 2022 10:30:31 GMT\r\n
content-encoding: br\r\n
content-type: application/javascript\r\n
Connection: keep-alive\r\n
server: tencent-cos\r\n
cache-control: max-age=31536000\r\n
content-length: 96194\r\n
\r\n
  • 第一行是状态行,由协议(HTTP/2)、状态码(200)、状态码的原因短语(OK)三部分构成

  • 其余是响应头,由头部字段名称(Connection) :值(keep-alive) 构成

  • 最后响应头与响应体之间还有一行\r\n的空行

本文实现的响应头,包含200、400、403、404四种状态码及其对应的原因短语

响应头部分有Connection、Content-type、Content-length三个字段

生成状态码的方法:

利用int stat(const char *path, struct stat *buf) 函数

//按location路径无法搜到文件,或搜到的是目录文件(404找不到)
if(stat(location.c_str(),&mmFileStat)<0||S_ISDIR(mmFileStat.st_mode))
{code=404;
}
else if (!(mmFileStat.st_mode&S_IROTH))//其他用户不可读(403禁止访问)
{code=403;
}

获取Content-type对应值的方法:

提取path的后缀,然后利用哈希表SUFFIX_TYPE,得到对应值(例如:文件后缀为html,则对应值应为text/html )

std::string HttpResponse::getFileType()
{size_t idx=path.find_last_of('.');if(idx==std::string::npos){return "text/plain";}std::string suffix=path.substr(idx);if(SUFFIX_TYPE.count(suffix)){return SUFFIX_TYPE.find(suffix)->second;}return "text/plain";
} 

其次是制作响应体:

响应体内应为path对应的文件,为了提高服务器从磁盘中读取响应文件的速度,采用mmap方法,建立私有的可读内存映射。

void* mmRet=mmap(0,mmFileStat.st_size,PROT_READ,MAP_PRIVATE,srcFd,0);

mmFileStat.st_size的值就是Content-length的对应值

HttpResponse类结构 httpresponse.h

#ifndef HTTPRESPONSE_H
#define HTTPRESPONSE_H#include <unordered_map>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>#include "../log/log.h"
#include "../buffer/buffer.h"class HttpResponse
{
public:HttpResponse();~HttpResponse();void init(const std::string& srcDir_,const std::string& path_,bool isKeepAlive_, int code_);void makeResponse(Buffer& buffer);void unmapFile();char* getfile();size_t getFileLen();private:void addStateLine(Buffer& buffer);void addHeader(Buffer& buffer);void addContent(Buffer& buffer);void errorHtml();std::string getFileType();int code;bool isKeepAlive;std::string path;std::string srcDir;char* mmFile;struct stat mmFileStat;static const std::unordered_map<std::string,std::string> SUFFIX_TYPE;static const std::unordered_map<int,std::string> CODE_STATUS;static const std::unordered_map<int,std::string> CODE_PATH;
};#endif // !HTTPRESPONSE_H

HttpResponse类实现 httpresponse.cpp

#include "httpresponse.h"const std::unordered_map<std::string,std::string> HttpResponse::SUFFIX_TYPE=
{{ ".html",  "text/html" },{ ".xml",   "text/xml" },{ ".xhtml", "application/xhtml+xml" },{ ".txt",   "text/plain" },{ ".rtf",   "application/rtf" },{ ".pdf",   "application/pdf" },{ ".word",  "application/nsword" },{ ".png",   "image/png" },{ ".gif",   "image/gif" },{ ".jpg",   "image/jpeg" },{ ".jpeg",  "image/jpeg" },{ ".au",    "audio/basic" },{ ".mpeg",  "video/mpeg" },{ ".mpg",   "video/mpeg" },{ ".avi",   "video/x-msvideo" },{ ".mp4",   "video/mp4" },{ ".gz",    "application/x-gzip" },{ ".tar",   "application/x-tar" },{ ".css",   "text/css "},{ ".js",    "text/javascript "}
};
const std::unordered_map<int,std::string> HttpResponse::CODE_STATUS=
{{ 200, "OK" },{ 400, "Bad Request" },{ 403, "Forbidden" },{ 404, "Not Found" },
};
const std::unordered_map<int,std::string> HttpResponse::CODE_PATH=
{{ 400, "/400.html" },{ 403, "/403.html" },{ 404, "/404.html" },
};HttpResponse::HttpResponse()
{code=-1;isKeepAlive=false;mmFile=nullptr;mmFileStat={0};Log::getInstance()->init();
}HttpResponse::~HttpResponse()
{unmapFile();
}void HttpResponse::unmapFile()//关闭内存映射
{if(mmFile){munmap(mmFile,mmFileStat.st_size);mmFile=nullptr;}
}void HttpResponse::init(const std::string& srcDir_,const std::string& path_, bool isKeepAlive_, int code_)
{assert(srcDir_!="");if(mmFile){unmapFile();}srcDir=srcDir_;code=code_;path=path_;isKeepAlive=isKeepAlive_;
}void HttpResponse::makeResponse(Buffer& buffer)
{std::string location=srcDir+path;//按location路径无法搜到文件,或搜到的是目录文件(404找不到)if(stat(location.c_str(),&mmFileStat)<0||S_ISDIR(mmFileStat.st_mode)){code=404;}else if (!(mmFileStat.st_mode&S_IROTH))//其他用户不可读(403禁止访问){code=403;}else if(code==-1){code=400;}errorHtml();//如果状态码是CODE_PATH中的400、403、404,则更改回送资源的路径pathaddStateLine(buffer);//添加状态行addHeader(buffer);//添加响应头addContent(buffer);//添加响应体
}void HttpResponse::errorHtml()//如果状态码是CODE_PATH中的400、403、404,则更改回送资源的路径path
{if(CODE_PATH.count(code)){path=CODE_PATH.find(code)->second;std::string location=srcDir+path;stat(location.c_str(),&mmFileStat);}
}void HttpResponse::addStateLine(Buffer& buffer)//添加状态行
{std::string status;if(CODE_STATUS.count(code)){status=CODE_STATUS.find(code)->second;}else{code=400;status=CODE_STATUS.find(400)->second;}buffer.append("HTTP/1.1 "+std::to_string(code)+" "+status+"\r\n");
}void HttpResponse::addHeader(Buffer& buffer)//添加响应头
{buffer.append("Connection: ");if(isKeepAlive){buffer.append("keep-alive\r\n");}else{buffer.append("close\r\n");}buffer.append("Content-type: "+getFileType()+"\r\n");
}void HttpResponse::addContent(Buffer& buffer)//添加响应体
{std::string location=srcDir+path;int srcFd=open(location.c_str(),O_RDONLY);if(srcFd<0){LOG_ERROR("%s","Response File NotFind!");return ;}//建立私有的可读内存映射,提高读取磁盘文件的速率void* mmRet=mmap(0,mmFileStat.st_size,PROT_READ,MAP_PRIVATE,srcFd,0);if(mmRet==MAP_FAILED){LOG_ERROR("%s","Response File NotFind!");return ;}mmFile=(char*)mmRet;close(srcFd);buffer.append("Content-length: "+std::to_string(mmFileStat.st_size)+"\r\n\r\n");
}std::string HttpResponse::getFileType()//获取请求资源的类型
{size_t idx=path.find_last_of('.');if(idx==std::string::npos){return "text/plain";}std::string suffix=path.substr(idx);if(SUFFIX_TYPE.count(suffix)){return SUFFIX_TYPE.find(suffix)->second;}return "text/plain";
} char* HttpResponse::getfile()//返回映射文件的句柄
{return mmFile;
}size_t HttpResponse::getFileLen()//返回映射文件的大小
{return mmFileStat.st_size;
}

生成HTTP响应报文相关推荐

  1. HTTP协议简介_请求消息/请求数据包/请求报文_响应消息/响应数据包/响应报文

    文章目录 HTTP 介绍 请求数据包/请求消息/请求报文 请求数据包解析 响应数据包/响应消息/响应报文 HTTP 介绍 概念:Hyper Text Transfer Protocol 超文本传输协议 ...

  2. 实现免密登录,设置只允许student1, student2用户登录,get和post的区别,HTTP状态码,HTTP请求报文和响应报文,HTTP是如何保持连接状态的

    1.实现免密登录 1创建密钥 [root@192 /]# su gzw [gzw@192 /]$ cd /home/gzw/.ssh [gzw@192 .ssh]$ ssh-keygen -t rsa ...

  3. 使用java解析Infor XA ERP SystemLink请求响应报文

    Infor XA ERP的SystemLink响应报文是一段比较复杂的xml,里面记录了操作是否成功的状态以及操作结果或者错误说明. 对SystemLink解析,就是从响应的xml报文里面解析出操作结 ...

  4. 使用 PHP 处理HTTP 响应报文

    HTTP Response 报文结构 HTTP Response 报文结构包括: 状态行包含 HTTP协议版本号.状态码.状态消息 Response Header包含HTTP响应的操作参数.heade ...

  5. 【项目学习】C++实现高并发服务器——代码学习(二)存储解析HTTP请求报文,创建响应报文

    项目来源:WebServer 上一篇:Reactor高并发模型 本文介绍以下功能的代码实现 利用标准库容器封装char,实现自动增长的缓冲区: 利用正则与状态机解析HTTP请求报文,实现处理静态资源的 ...

  6. Wireshark 抓包分析 HTTP 请求、响应报文格式

    文章目录 报文结构 HTTP 请求报文的请求行 请求方法 GET/HEAD POST/PUT 其他方法 URI URI 的格式 URI 的编码 HTTP 响应报文的状态行 状态码 HTTP 请求.响应 ...

  7. HTTP请求响应系列02_响应报文的详解

    响应报文 1.响应报文的详解 上篇文字讲的"请求报文",本篇主要解释响应报文包括的内容. 响应报文的内容也包括三部分,分别是: 响应行, 响应头, 响应体.这三部分放的都是信息.是 ...

  8. HTTP请求报文和HTTP响应报文(转)

    原文地址:http://blog.csdn.net/zhangliang_571/article/details/23508953 HTTP报文是面向文本的,报文中的每一个字段都是一些ASCII码串, ...

  9. java 报文请求_http 请求报文和响应报文编写 (java socket实例)

    http 请求头由三部分组成:请求行.请求头部.请求体 GET / HTTP/1.1\r\n Host: 114.55.40.20\r\n Content-Type: text/html;charse ...

最新文章

  1. 【Luogu】P3356火星探险问题(费用流)
  2. java开发可重用代码包工具包_[Java教程]彻底搞懂Java开发工具包(JDK)安装及环境变量配置...
  3. Apache(httpd)配置--防盗链配置和访问控制
  4. linux时间格式怎么写,linux基础--时间格式
  5. MATLAB编程与应用系列-关于MATLAB编程入门教程的总体编写安排
  6. 线段树-Count on a Treap-神题
  7. java final 初始化_[转]java static final 初始化
  8. Python中sorted()函数的高级用法详解
  9. 把CS文件编译成dll文件
  10. mac使用eclipse创建java_【Java】Mac上使用Eclipse创建Java项目的一般步骤
  11. 动力节点Docker视频教程从入门到精通
  12. bubu PC端的应用商店1 -架构
  13. 高频信号发生器设计—电容三点式振荡电路
  14. vs code c语言安装视频,vscode怎样安装c语言环境
  15. mybatis在关联映射中,引入外部xml文件中定义的对象
  16. 第三方支付如何玩转大数据
  17. 微信小程序 图片上传与内容安全审核
  18. matlab差分阶跃响应,matlab在DSP中的应用(四)---离散系统的冲激响应和阶跃响应...
  19. winSCP 集成PuTTY附下载
  20. 游戏市场阴影下的游戏手机厂商,和他们无法触碰的未来

热门文章

  1. ae教程 (六)人物滤镜 (二)清新粉色调
  2. Oracle11g限制ip访问数据库,ORACLE 限制特定IP访问数据库
  3. C#操作IIS程序池及站点的创建配置(转)
  4. 虚拟机利用与叠加带宽
  5. java 正则表达式替换多个全角空格为一个半角空格_去掉字符串两端的全角空格和半角空格(含源代码)...
  6. 人工智能:PyTorch深度学习框架介绍
  7. 电脑登录qq但是打不开网页的解决办法(转载)
  8. 鱼骨图分析法实际案例_技术前沿 | 基于鱼骨图分析标准实施偏差成因的应用研究...
  9. 解释某宝的一段混淆视听的代码
  10. 北京公户京牌指标相关问题详解