【Linux网络】Http服务优化 - 增加请求后缀、状态码描述、重定向、自动跳转及注册多功能服务

📢博客主页:https://blog.csdn.net/2301_779549673
📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson
📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
📢本文由 JohnKi 原创,首发于 CSDN🙉
📢未来很长,值得我们全力奔赴更美好的生活✨

在这里插入图片描述

在这里插入图片描述

文章目录

  • 🏳️‍🌈一、增加请求后缀
    • 1.1 HttpRequest 类
    • 1.2 HttpHandler 类
  • 🏳️‍🌈二、状态码描述 及 自动跳转404
    • 2.1 状态码描述
    • 2.2 自动跳转404
  • 🏳️‍🌈三、重定向状态码
  • 🏳️‍🌈四、注册等多功能服务
    • 4.1 HttpRequest 类
    • 4.2 HttpHandler 类
    • 4.3 TcpServer.cpp
    • 4.4 测试
  • 👥总结


🏳️‍🌈一、增加请求后缀

我们在浏览器上访问我们自己的服务端时,会遇到客户端发送来的请求,想要访问 1.jpg 或者 default.html 因此我们可以将这个后缀给整理一下,通过日志打印告诉我们自己目标想要访问的资源在当前的哪里。

1.1 HttpRequest 类

我们在这个类里进行如下操作

  1. 添加成员变量 _suffix
  2. 在请求行解析方法中,增添一段,通过后缀分隔符 "." ,来找到我们的后缀,没有找到就返回默认后缀
  3. 添加函数方法,获取当前请求的后缀名
const static std::string _suffixsep = ".";                      // 后缀分隔符    class HttpRequest {
private:// 解析请求行void PraseReqLine() {// 以空格为分隔符,不断读取std::stringstream ss(_req_line);ss >> _method >> _url >> _version;_path += _url;// 处理url,如果是根目录,则返回默认路径if (_url == "/")_path += _default_path;// 获取后缀auto pos = _path.rfind(_suffixsep);if (pos == std::string::npos)_suffix = ".default";else_suffix = _path.substr(pos);}public:std::string Suffix() {LOG(LogLevel::INFO) << "client want suffix : " << _suffix;return _suffix;}
}

1.2 HttpHandler 类

这里我们需要先知道一个概念 - MIMIE

MIME 是一种 ​互联网标准,最初设计用于扩展电子邮件协议(如 SMTP),使其能传输非文本数据(如图片、音频)。后被 HTTP 协议广泛采用,用于标识网络资源的 ​数据类型。

  • .html → text/html(HTML 文档)
  • .jpg → image/jpeg(JPEG 图片)
  • .json → application/json(JSON 数据)

这个类中我们需要增加一个后缀映射,并将其添加在返回报文的报头列表中

1, 增加成员变量 后缀后缀存储 的映射
2.`构造函数 时,初始化映射
3. 处理请求时,将映射结果添加到响应报头中

class HttpHandler {
public:HttpHandler() {_mime_type.insert(std::make_pair(".html", "text/html"));_mime_type.insert(std::make_pair(".jpg", "image/jpg"));_mime_type.insert(std::make_pair(".png", "image/png"));_mime_type.insert(std::make_pair(".default", "text/html"));}std::string HandleRequest(std::string req) {std::cout << "------------------------------------" << std::endl;std::cout << req;HttpRequest req_obj;req_obj.Descrialize(req);std::string content = GetFileContent(req_obj.Path());if (content.empty())return std::string();HttpResponse rsp;rsp.AddCode(200);rsp.AddHeader("Content-Length", std::to_string(content.size()));rsp.AddHeader("Content-type", _mime_type[req_obj.Suffix()]);rsp.AddBodyText(content);return rsp.Serialize();}
private:std::unordered_map<std::string, std::string> _mime_type;
};

🏳️‍🌈二、状态码描述 及 自动跳转404

前面的文章中我们已经知道了状态码描述的存在,但是没有可利用过,这里再介绍一下这个状态码,添加一个状态码的映射并且根据访问内容,去判断要不要显示404界面

2.1 状态码描述

这里需要进行两方面的更改,一个是 HttpResponse一个是 HttpHandler 的构造和成员变量

HttpHandler 中我们添加 状态码状态码描述映射,然后在构造中表示出来

class HttpHandler {
public:HttpHandler() {_mime_type.insert(std::make_pair(".html", "text/html")); // HTML 类型_mime_type.insert(std::make_pair(".jpg", "image/jpeg")); // JPEG 图片_mime_type.insert(std::make_pair(".png", "image/png"));  // PNG 图片_mime_type.insert(std::make_pair(".default", "text/html")); // 默认文本类型_status_code_desc.insert(std::make_pair(100, "Continue"));_status_code_desc.insert(std::make_pair(200, "OK"));_status_code_desc.insert(std::make_pair(201, "Created"));_status_code_desc.insert(std::make_pair(404, "Not Found"));}
private:std::unordered_map<int, std::string> _status_code_desc;
};

HttpResponse 中的 AddCode 方法,我们之前默认是不论什么都是 OK,现在我们对其进行专属化处理

// 添加 状态码 和 状态码描述
void AddCode(int code, std::string desc) {_status_code = code;_desc = desc;
}

2.2 自动跳转404

我们在 HttpHandlerHandleRequest 方法中,当判定访问的路径内容为空时,就将这个路径改成 404.html

std::string HandleRequest(std::string req) {std::cout << "------------------------------------" << std::endl;std::cout << req;HttpRequest req_obj;req_obj.Descrialize(req);std::string content = GetFileContent(req_obj.Path());HttpResponse rsp;if (content.empty()) {content = GetFileContent("wwwroot/404.html");rsp.AddCode(404, _status_code_desc[404]);rsp.AddHeader("Content-Length", std::to_string(content.size()));rsp.AddHeader("Content-type", _mime_type[".default"]);rsp.AddBodyText(content);} else {rsp.AddCode(200, _status_code_desc[200]);rsp.AddHeader("Content-Length", std::to_string(content.size()));rsp.AddHeader("Content-type", _mime_type[req_obj.Suffix()]);rsp.AddBodyText(content);}return rsp.Serialize();
}

🏳️‍🌈三、重定向状态码

在这里插入图片描述

HTTP 状态码 301(永久重定向)和 302(临时重定向)都依赖 Location 选项。

无论是 HTTP 301 还是 HTTP 302 重定向,都需要依赖 Location 选项来指定资源的新位置。这个 Location 选项是一个标准的 HTTP 响应头部,用于告诉浏览器应该将请求重定向到哪个新的 URL 地址。

我们现在 default.html 中添加 测试重定向 的选项

在这里插入图片描述

我们测试永久重定向,将当前的网址重定向到 qq.com

std::string HandleRequest(std::string req) {std::cout << "------------------------------------" << std::endl;std::cout << req;HttpRequest req_obj;req_obj.Descrialize(req);HttpResponse rsp;if (req_obj.Url() == "/redirect") {// 重定向处理std::string redirect_path = "https://www.qq.com";rsp.AddCode(302, _status_code_desc[302]);rsp.AddHeader("Location", redirect_path);rsp.AddHeader("Content-Type", "text/plain"); // 添加 Content-Typersp.AddHeader("Content-Length", "0");        // 显式设置内容长度为 0rsp.AddBodyText("");                         // 确保响应体为空} else {std::string content = GetFileContent(req_obj.Path());if (content.empty()) {content = GetFileContent("wwwroot/404.html");rsp.AddCode(404, _status_code_desc[404]);rsp.AddHeader("Content-Length", std::to_string(content.size()));rsp.AddHeader("Content-type", _mime_type[".default"]);rsp.AddBodyText(content);} else {rsp.AddCode(200, _status_code_desc[200]);rsp.AddHeader("Content-Length", std::to_string(content.size()));rsp.AddHeader("Content-type", _mime_type[req_obj.Suffix()]);rsp.AddBodyText(content);}}return rsp.Serialize();
}

在这里插入图片描述

🏳️‍🌈四、注册等多功能服务

因为存在两种主要的提交方式,分别是 POSTGET,因此参数的位置会不一样,

GET 下,位于 网址 的 后面

在这里插入图片描述

POST 下,位于请求正文中

所以我们要根据不同的情况,分出响应的 参数,以及路径

4.1 HttpRequest 类

需要改的主要有三部分

  1. 增加新的成员变量_args 用来记录参数,_isexcute 用来记录是否有参数
  2. 构造函数中给 _isexcute 默认为false
  3. 更改 Descrialize 细节,使其区分 GETPOST,并且能够准确提取出 _args_path
class HttpRequest{private:public:HttpRequest() : _blank_line(_base_sep), _path(_prefix_path), _isexcute(false) {}void Descrialize(std::string& reqstr){// 基本的反序列化_req_line = GetLine(reqstr);    // 读取第一行请求行// 请求报头std::string header;do{header = GetLine(reqstr);// 如果既不是空,也不是空行,就是请求报头,加入到请求报头列表中if(header.empty()) break;else if(header == _base_sep) break;_req_headers.push_back(header);}while(true);// 正文if(!reqstr.empty())_req_body = reqstr;// 进一步反序列化请求行PraseReqLine();// 分割请求报头,获取键值对PraseHeader(); // 判断是否需要动态执行if(_method == "POST"){_isexcute = true;_args = _req_body;LOG(LogLevel::INFO) << "POST _path : " << _path;LOG(LogLevel::INFO) << "POST _args : " << _args;} else if(_method == "GET"){auto pos = _path.find("?");if(pos != std::string::npos){_isexcute = true;_args = _path.substr(pos + 1);_path = _path.substr(0, pos);LOG(LogLevel::INFO) << "GET _path : " << _path;LOG(LogLevel::INFO) << "GET _args : " << _args;}}}std::string Args(){LOG(LogLevel::INFO) << "client want _args : " << _args;  return _args;}bool Isexecute(){LOG(LogLevel::INFO) << "client want _isexcute : " << _isexcute;  return _isexcute;}private:bool _isexcute;                              // 是否需要动态执行std::string _args;                           // 动态执行的参数};

4.2 HttpHandler 类

增加功能路由表也就是映射目标路径和方法unoredered_map。同时也要构建能够处理相应操作的回调函数类型

using http_handler_t = std::function<HttpResponse(HttpRequest&)>;
std::unordered_map<std::string, http_handler_t> _route; // 功能路由表

增加注册服务的相关功能

	// 注册服务功能void RegisterHandler(std::string funcname, http_handler_t service) {std::string name = _prefix_path + funcname;_route.insert(std::make_pair(name, service));}// 判断是否存在该功能bool HasHandler(std::string funcname) {auto iter = _route.find(funcname);if (iter == _route.end())return false;elsereturn true;}

将http请求处理主要分为三块

  1. 重定向处理
  2. 动态操作处理
  3. 静态页面变化处理
std::string HandleRequest(std::string req) {std::cout << "------------------------------------" << std::endl;std::cout << req;HttpRequest req_obj;req_obj.Descrialize(req);HttpResponse rsp;if (req_obj.Url() == "/redirect") {LOG(LogLevel::DEBUG) << "重定向服务";// 重定向处理std::string redirect_path = "https://www.qq.com";rsp.AddCode(302, _status_code_desc[302]);rsp.AddHeader("Location", redirect_path);rsp.AddHeader("Content-Type", "text/plain"); // 添加 Content-Typersp.AddHeader("Content-Length", "0");        // 显式设置内容长度为 0rsp.AddBodyText("");                         // 确保响应体为空} else if (req_obj.Isexecute()) {LOG(LogLevel::DEBUG) << "注册服务";if (HasHandler(req_obj.Path())) {LOG(LogLevel::DEBUG) << "找到注册服务";rsp = _route[req_obj.Path()](req_obj);} else {LOG(LogLevel::DEBUG) << "没有找到注册服务";std::string content = GetFileContent("wwwroot/404.html");rsp.AddCode(404, _status_code_desc[404]);rsp.AddHeader("Content-Length", std::to_string(content.size()));rsp.AddHeader("Content-type", _mime_type[".default"]);rsp.AddBodyText(content);}} else {LOG(LogLevel::DEBUG) << "静态页面服务";std::string content = GetFileContent(req_obj.Path());if (content.empty()) {content = GetFileContent("wwwroot/404.html");rsp.AddCode(404, _status_code_desc[404]);rsp.AddHeader("Content-Length", std::to_string(content.size()));rsp.AddHeader("Content-type", _mime_type[".default"]);rsp.AddBodyText(content);} else {rsp.AddCode(200, _status_code_desc[200]);rsp.AddHeader("Content-Length", std::to_string(content.size()));rsp.AddHeader("Content-type", _mime_type[req_obj.Suffix()]);rsp.AddBodyText(content);}}return rsp.Serialize();
}

4.3 TcpServer.cpp

这里我们需要将注册服务具体化,并添加到 功能路由表

现实生活中,我们还需要对这个传进来的参数(用户名、密码等)进行序列化,到数据库中查找等操作,这里就不拓展了,简简单单地使用 success.html 界面表示我们登录成功就行了

HttpResponse Login(HttpRequest& req){HttpResponse rsp;LOG(LogLevel::INFO) << "进入登录模块" << req.Path() << ", " << req.Args();std::string req_args = req.Args();// 1. 解析参数格式,得到要的参数// 2. 访问数据库,验证对应的用户是否是合法用户,以及...// 3. 登录成功HttpHandler httphandler;std::string content = httphandler.GetFileContent("wwwroot/success.html");rsp.AddCode(200, "OK");rsp.AddHeader("Content-Length", std::to_string(content.size()));rsp.AddHeader("Content-Type", "text/html");rsp.AddHeader("Set-Cokkie", "req_args");rsp.AddBodyText(content);return rsp;
}

4.4 测试

当 ·login 方法是 GET
在这里插入图片描述

在这里插入图片描述

当是 POST
在这里插入图片描述

在这里插入图片描述


👥总结

本篇博文对 【Linux网络】Http服务优化 - 增加请求后缀、状态码描述、重定向、自动跳转及注册多功能服务 做了一个较为详细的介绍,不知道对你有没有帮助呢

觉得博主写得还不错的三连支持下吧!会继续努力的~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/80719.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AIGC(生成式AI)试用 32 -- AI做软件程序测试 3

总结之前的AI做程序测试过程&#xff0c;试图优化提问方式&#xff0c;整合完成的AI程序测试提问&#xff0c;探索更多可能的AI测试 AIGC&#xff08;生成式AI&#xff09;试用 30 -- AI做软件程序测试 1 AIGC&#xff08;生成式AI&#xff09;试用 31 -- AI做软件程序…

C语言实现迪杰斯特拉算法进行路径规划

使用C语言实现迪杰斯特拉算法进行路径规划 迪杰斯特拉算法是一种用于寻找加权图中最短路径的经典算法。它特别适合用于计算从一个起点到其他所有节点的最短路径&#xff0c;前提是图中的边权重为非负数。 一、迪杰斯特拉算法的基本原理 迪杰斯特拉算法的核心思想是“贪心法”…

引领印尼 Web3 变革:Mandala Chain 如何助力 1 亿用户迈向数字未来?

当前 Web3 的发展正处于关键转折点&#xff0c;行业亟需吸引新用户以推动 Web3 的真正大规模采用。然而&#xff0c;大规模采用面临着核心挑战&#xff1a;数据泄露风险、集中存储的安全漏洞、跨系统互操作性障碍&#xff0c;以及低效的服务访问等问题。如何才能真正突破这些瓶…

WebSocket是h5定义的,双向通信,节省资源,更好的及时通信

浏览器和服务器之间的通信更便利&#xff0c;比http的轮询等效率提高很多&#xff0c; WebSocket并不是权限的协议&#xff0c;而是利用http协议来建立连接 websocket必须由浏览器发起请求&#xff0c;协议是一个标准的http请求&#xff0c;格式如下 GET ws://example.com:3…

Kaamel白皮书:IoT设备安全隐私评估实践

1. IoT安全与隐私领域的现状与挑战 随着物联网技术的快速发展&#xff0c;IoT设备在全球范围内呈现爆发式增长。然而&#xff0c;IoT设备带来便捷的同时&#xff0c;也引发了严峻的安全与隐私问题。根据NSF&#xff08;美国国家科学基金会&#xff09;的研究表明&#xff0c;I…

php安装swoole扩展

PHP安装swoole扩展 Swoole官网 安装准备 安装前必须保证系统已经安装了下列软件 4.8 版本需要 PHP-7.2 或更高版本5.0 版本需要 PHP-8.0 或更高版本6.0 版本需要 PHP-8.1 或更高版本gcc-4.8 或更高版本makeautoconf 安装Swool扩展 安装官方文档安装后需要再php.ini中增加…

服务器传输数据存储数据建议 传输慢的原因

一、JSON存储的局限性 1. 性能瓶颈 全量读写&#xff1a;JSON文件通常需要整体加载到内存中才能操作&#xff0c;当数据量大时&#xff08;如几百MB&#xff09;&#xff0c;I/O延迟和内存占用会显著增加。 无索引机制&#xff1a;查找数据需要遍历所有条目&#xff08;时间复…

Android四大核心组件

目录 一、为什么需要四大组件&#xff1f; 二、Activity&#xff1a;看得见的界面 核心功能 生命周期图解 代码示例 三、Service&#xff1a;看不见的劳动者 两大类型 生命周期对比 注意陷阱 四、BroadcastReceiver&#xff1a;消息传递专员 两种注册方式 广播类型 …

「Mac畅玩AIGC与多模态01」架构篇01 - 展示层到硬件层的架构总览

一、概述 AIGC&#xff08;AI Generated Content&#xff09;系统由多个结构层级组成&#xff0c;自上而下涵盖交互界面、API 通信、模型推理、计算框架、底层驱动与硬件支持。本篇梳理 AIGC 应用的六层体系结构&#xff0c;明确各组件在系统中的职责与上下游关系&#xff0c;…

[MERN 项目实战] MERN Multi-Vendor 电商平台开发笔记(v2.0 从 bug 到结构优化的工程记录)

[MERN 项目实战] MERN Multi-Vendor 电商平台开发笔记&#xff08;v2.0 从 bug 到结构优化的工程记录&#xff09; 其实之前没想着这么快就能把 2.0 的笔记写出来的&#xff0c;之前的预期是&#xff0c;下一个阶段会一直维持到将 MERN 项目写完&#xff0c;毕竟后期很多东西都…

互斥量函数组

头文件 #include <pthread.h> pthread_mutex_init 函数原型&#xff1a; int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); 函数参数&#xff1a; mutex&#xff1a;指向要初始化的互斥量的指针。 attr&#xf…

互联网的下一代脉搏:深入理解 QUIC 协议

互联网的下一代脉搏&#xff1a;深入理解 QUIC 协议 互联网是现代社会的基石&#xff0c;而数据在其中高效、安全地传输是其运转的关键。长期以来&#xff0c;传输层的 TCP&#xff08;传输控制协议&#xff09;一直是互联网的主力军。然而&#xff0c;随着互联网应用场景的日…

全球城市范围30米分辨率土地覆盖数据(1985-2020)

Global urban area 30 meter resolution land cover data (1985-2020) 时间分辨率年空间分辨率10m - 100m共享方式保护期 277 天 5 时 42 分 9 秒数据大小&#xff1a;8.98 GB数据时间范围&#xff1a;1985-2020元数据更新时间2024-01-11 数据集摘要 1985~2020全球城市土地覆…

【Vue】单元测试(Jest/Vue Test Utils)

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Vue 文章目录 1. Vue 单元测试简介1.1 为什么需要单元测试1.2 测试工具介绍 2. 环境搭建2.1 安装依赖2.2 配置 Jest 3. 编写第一个测试3.1 组件示例3.2 编写测试用例3.3 运行测试 4. Vue Test Utils 核心 API4.1 挂载组件4.2 常…

数据湖的管理系统管什么?主流产品有哪些?

一、数据湖的管理系统管什么&#xff1f; 数据湖的管理系统主要负责管理和优化存储在数据湖中的大量异构数据&#xff0c;确保这些数据能够被有效地存储、处理、访问和治理。以下是数据湖管理系统的主要职责&#xff1a; 数据摄入管理&#xff1a;管理系统需要支持从多种来源&…

英文中日期读法

英文日期的读法和写法因地区&#xff08;英式英语与美式英语&#xff09;和正式程度有所不同&#xff0c;以下是详细说明&#xff1a; 一、日期格式 英式英语 (日-月-年) 写法&#xff1a;1(st) January 2023 或 1/1/2023读法&#xff1a;"the first of January, twenty t…

衡量矩阵数值稳定性的关键指标:矩阵的条件数

文章目录 1. 定义2. 为什么要定义条件数&#xff1f;2.1 分析线性系统 A ( x Δ x ) b Δ b A(x \Delta x) b \Delta b A(xΔx)bΔb2.2 分析线性系统 ( A Δ A ) ( x Δ x ) b (A \Delta A)(x \Delta x) b (AΔA)(xΔx)b2.3 定义矩阵的条件数 3. 性质及几何意义3…

4月22日复盘-开始卷积神经网络

4月24日复盘 一、CNN 视觉处理三大任务&#xff1a;图像分类、目标检测、图像分割 上游&#xff1a;提取特征&#xff0c;CNN 下游&#xff1a;分类、目标、分割等&#xff0c;具体的业务 1. 概述 ​ 卷积神经网络是深度学习在计算机视觉领域的突破性成果。在计算机视觉领…

【网络原理】从零开始深入理解TCP的各项特性和机制.(三)

上篇介绍了网络原理传输层TCP协议的知识,本篇博客给大家带来的是网络原理剩余的内容, 总体来说,这部分内容没有上两篇文章那么重要,本篇知识有一个印象即可. &#x1f40e;文章专栏: JavaEE初阶 &#x1f680;若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分…

解决qnn htp 后端不支持boolean 数据类型的方法。

一、背景 1.1 问题原因 Qnn 模型在使用fp16的模型转换不支持类型是boolean的cast 算子&#xff0c;因为 htp 后端支持量化数据类型或者fp16&#xff0c;不支持boolean 类型。 ${QNN_SDK_ROOT_27}/bin/x86_64-linux-clang/qnn-model-lib-generator -c ./bge_small_fp16.cpp -b …