对单位网站的要求,佛山美容院网站建设,企业管理培训课程内容,黄页软件app开发文章目录 一、HttpContext模块二、HttpServer模块三、HttpContext模块实现思想#xff08;一#xff09;功能#xff08;二#xff09;意义#xff08;三#xff09;接口 四、HttpServer模块实现思想#xff08;一#xff09;功能#xff08;二#xff09;意义#… 文章目录 一、HttpContext模块二、HttpServer模块三、HttpContext模块实现思想一功能二意义三接口 四、HttpServer模块实现思想一功能二意义三分析 五、代码 一、HttpContext模块 要实现渐变的搭建HTTP服务器所需要提供的要素和功能
要素
1. GET请求的路由映射表
2. POST请求的路由映射表
3. PUT请求的路由映射表
4. DELETE请求的路由映射表 —— 路由映射表记录对应请求方法的请求的处理函数映射关系
5. 高性能TCP服务器—— 进行连接的IO操作
6. 静态资源相对根目录 —— 实现静态资源的处理
接口
服务器处理流程
1. 从socket接受数据放到接受缓冲区
2. 调用onmessage回调函数进行业务处理
3. 对请求进行介意得到了一个HTTPREQUEST结构包含了所有的请求要素!
4. 进行请求的路由映射 —— 找到对应请求的处理方法1. 静态资源请求 —— 一些实体文件资源的请求 html,image将静态资源文件的数据读取出来填充到HTTPresponse结构中2. 功能性请求 —— 在请求路由映射表中查找处理函数找到了则执行函数具体的业务请求并进行HTTPREsponse结构的数据填充
5. 对静态资源请求——功能性请求处理完毕后得到一个填充了相应信息的httpResponse 的对象组织http响应格式进行发送
接口添加请求—— 处理函数映射信息GET/POST/PUT/DELETE)设置静态资源根目录设置是否启动超时连接关闭设置线程池中线程数量启动服务器OnConnected - 用于给TcpServer设置协议上下文OnMessage - 用于进行缓冲区数据解析处理获取上下文进行缓冲区数据对象请求的路由查 找静态资源请求查找和处理功能性请求查找和处理组织响应进程回复
二、HttpServer模块 三、HttpContext模块实现思想
一功能
记录HTTP请求的接受和处理进度。
二意义
有可能出现接收的数据并不是一条完整的HTTP请求数据也就是请求的处理需要在多次受到数据之后才能处理完成因此在每次处理的时候就需要将进度处理记录下来以便于下次从当前进度继续向下处理。
三接口
接收并且处理数据接受请求行解析请求行接收头部解析头部接受正文返回解析完成的请求信息
四、HttpServer模块实现思想
一功能
对于HTTP协议支持所有模块的整合
二意义
让HTTP服务器的搭建变得更加简单
三分析
HttpServer模块:用于实现HTTP服务器的搭建
表中记录了针对哪个请求应该使用哪个函数来进行业务处理的映射关系 当服务器收到了一一个请求就在请求路由表中查找有没有对应请求的处理函数如果有则执行对应的处理函数即可说白了什么请求怎么处理由用户来设定服务器收到了请求只需要执行函数即可,这样做的好处:用户只需要实现业务处理函数,然后将请求与处理函数的映射关系,添加到服务器中而服务器只需要接收数据解析数据查找路由表映射关系执行业务处理函数。
五、代码
HttpResponse class HttpResponse {public:int _statu;bool _redirect_flag;std::string _body;std::string _redirect_url;std::unordered_mapstd::string, std::string _headers;public:HttpResponse():_redirect_flag(false), _statu(200) {}HttpResponse(int statu):_redirect_flag(false), _statu(statu) {} void ReSet() {_statu 200;_redirect_flag false;_body.clear();_redirect_url.clear();_headers.clear();}//插入头部字段void SetHeader(const std::string key, const std::string val) {_headers.insert(std::make_pair(key, val));}//判断是否存在指定头部字段bool HasHeader(const std::string key) {auto it _headers.find(key);if (it _headers.end()) {return false;}return true;}//获取指定头部字段的值std::string GetHeader(const std::string key) {auto it _headers.find(key);if (it _headers.end()) {return ;}return it-second;}void SetContent(const std::string body, const std::string type text/html) {_body body;SetHeader(Content-Type, type);}void SetRedirect(const std::string url, int statu 302) {_statu statu;_redirect_flag true;_redirect_url url;}//判断是否是短链接bool Close() {// 没有Connection字段或者有Connection但是值是close则都是短链接否则就是长连接if (HasHeader(Connection) true GetHeader(Connection) keep-alive) {return false;}return true;}
};
HttpServer模块
class HttpServer {private:using Handler std::functionvoid(const HttpRequest , HttpResponse *);using Handlers std::vectorstd::pairstd::regex, Handler;Handlers _get_route;Handlers _post_route;Handlers _put_route;Handlers _delete_route;std::string _basedir; //静态资源根目录TcpServer _server;private:void ErrorHandler(const HttpRequest req, HttpResponse *rsp) {//1. 组织一个错误展示页面std::string body;body html;body head;body meta http-equivContent-Type contenttext/html;charsetutf-8;body /head;body body;body h1;body std::to_string(rsp-_statu);body ;body Util::StatuDesc(rsp-_statu);body /h1;body /body;body /html;//2. 将页面数据当作响应正文放入rsp中rsp-SetContent(body, text/html);}//将HttpResponse中的要素按照http协议格式进行组织发送void WriteReponse(const PtrConnection conn, const HttpRequest req, HttpResponse rsp) {//1. 先完善头部字段if (req.Close() true) {rsp.SetHeader(Connection, close);}else {rsp.SetHeader(Connection, keep-alive);}if (rsp._body.empty() false rsp.HasHeader(Content-Length) false) {rsp.SetHeader(Content-Length, std::to_string(rsp._body.size()));}if (rsp._body.empty() false rsp.HasHeader(Content-Type) false) {rsp.SetHeader(Content-Type, application/octet-stream);}if (rsp._redirect_flag true) {rsp.SetHeader(Location, rsp._redirect_url);}//2. 将rsp中的要素按照http协议格式进行组织std::stringstream rsp_str;rsp_str req._version std::to_string(rsp._statu) Util::StatuDesc(rsp._statu) \r\n;for (auto head : rsp._headers) {rsp_str head.first : head.second \r\n;}rsp_str \r\n;rsp_str rsp._body;//3. 发送数据conn-Send(rsp_str.str().c_str(), rsp_str.str().size());}bool IsFileHandler(const HttpRequest req) {// 1. 必须设置了静态资源根目录if (_basedir.empty()) {return false;}// 2. 请求方法必须是GET / HEAD请求方法if (req._method ! GET req._method ! HEAD) {return false;}// 3. 请求的资源路径必须是一个合法路径if (Util::ValidPath(req._path) false) {return false;}// 4. 请求的资源必须存在,且是一个普通文件// 有一种请求比较特殊 -- 目录/, /image/ 这种情况给后边默认追加一个 index.html// index.html /image/a.png// 不要忘了前缀的相对根目录,也就是将请求路径转换为实际存在的路径 /image/a.png - ./wwwroot/image/a.pngstd::string req_path _basedir req._path;//为了避免直接修改请求的资源路径因此定义一个临时对象if (req._path.back() /) {req_path index.html;}if (Util::IsRegular(req_path) false) {return false;}return true;}//静态资源的请求处理 --- 将静态资源文件的数据读取出来放到rsp的_body中, 并设置mimevoid FileHandler(const HttpRequest req, HttpResponse *rsp) {std::string req_path _basedir req._path;if (req._path.back() /) {req_path index.html;}bool ret Util::ReadFile(req_path, rsp-_body);if (ret false) {return;}std::string mime Util::ExtMime(req_path);rsp-SetHeader(Content-Type, mime);return;}//功能性请求的分类处理void Dispatcher(HttpRequest req, HttpResponse *rsp, Handlers handlers) {//在对应请求方法的路由表中查找是否含有对应资源请求的处理函数有则调用没有则发挥404//思想路由表存储的时键值对 -- 正则表达式 处理函数//使用正则表达式对请求的资源路径进行正则匹配匹配成功就使用对应函数进行处理// /numbers/(\d) /numbers/12345for (auto handler : handlers) {const std::regex re handler.first;const Handler functor handler.second;bool ret std::regex_match(req._path, req._matches, re);if (ret false) {continue;}return functor(req, rsp);//传入请求信息和空的rsp执行处理函数}rsp-_statu 404;}void Route(HttpRequest req, HttpResponse *rsp) {//1. 对请求进行分辨是一个静态资源请求还是一个功能性请求// 静态资源请求则进行静态资源的处理// 功能性请求则需要通过几个请求路由表来确定是否有处理函数// 既不是静态资源请求也没有设置对应的功能性请求处理函数就返回405if (IsFileHandler(req) true) {//是一个静态资源请求, 则进行静态资源请求的处理return FileHandler(req, rsp);}if (req._method GET || req._method HEAD) {return Dispatcher(req, rsp, _get_route);}else if (req._method POST) {return Dispatcher(req, rsp, _post_route);}else if (req._method PUT) {return Dispatcher(req, rsp, _put_route);}else if (req._method DELETE) {return Dispatcher(req, rsp, _delete_route);}rsp-_statu 405;// Method Not Allowedreturn ;}//设置上下文void OnConnected(const PtrConnection conn) {conn-SetContext(HttpContext());DBG_LOG(NEW CONNECTION %p, conn.get());}//缓冲区数据解析处理void OnMessage(const PtrConnection conn, Buffer *buffer) {while(buffer-ReadAbleSize() 0){//1. 获取上下文HttpContext *context conn-GetContext()-getHttpContext();//2. 通过上下文对缓冲区数据进行解析得到HttpRequest对象// 1. 如果缓冲区的数据解析出错就直接回复出错响应// 2. 如果解析正常且请求已经获取完毕才开始去进行处理context-RecvHttpRequest(buffer);HttpRequest req context-Request();HttpResponse rsp(context-RespStatu());if (context-RespStatu() 400) {//进行错误响应关闭连接ErrorHandler(req, rsp);//填充一个错误显示页面数据到rsp中WriteReponse(conn, req, rsp);//组织响应发送给客户端context-ReSet();buffer-MoveReadOffset(buffer-ReadAbleSize());//出错了就把缓冲区数据清空conn-Shutdown();//关闭连接return;}if (context-RecvStatu() ! RECV_HTTP_OVER) {//当前请求还没有接收完整,则退出等新数据到来再重新继续处理return;}//3. 请求路由 业务处理Route(req, rsp);//4. 对HttpResponse进行组织发送WriteReponse(conn, req, rsp);//5. 重置上下文context-ReSet();//6. 根据长短连接判断是否关闭连接或者继续处理if (rsp.Close() true) conn-Shutdown();//短链接则直接关闭}return;}public:HttpServer(int port, int timeout DEFALT_TIMEOUT):_server(port) {_server.EnableInactiveRelease(timeout);_server.SetConnectedCallback(std::bind(HttpServer::OnConnected, this, std::placeholders::_1));_server.SetMessageCallback(std::bind(HttpServer::OnMessage, this, std::placeholders::_1, std::placeholders::_2));}void SetBaseDir(const std::string path) {assert(Util::IsDirectory(path) true);_basedir path;}/*设置/添加请求请求的正则表达与处理函数的映射关系*/void Get(const std::string pattern, const Handler handler) {_get_route.push_back(std::make_pair(std::regex(pattern), handler));}void Post(const std::string pattern, const Handler handler) {_post_route.push_back(std::make_pair(std::regex(pattern), handler));}void Put(const std::string pattern, const Handler handler) {_put_route.push_back(std::make_pair(std::regex(pattern), handler));}void Delete(const std::string pattern, const Handler handler) {_delete_route.push_back(std::make_pair(std::regex(pattern), handler));}void SetThreadCount(int count) {_server.SetThreadCount(count);}void Listen() {_server.Start();}
};