认识http的方法、Header、状态码以及简单实现一个http的业务逻辑

文章目录

  • http的方法
  • http状态码
  • http重定向
  • http常见Header
  • 实现简单业务逻辑
    • Protocol.hpp
    • Util.hpp
    • Server.hpp
    • Server.cc
  • 效果

http的方法

方法说明支持的HTTP版本
GET获取资源1.0/1.1
POST传输实体主体1.0/1.1
PUT传输文件1.0/1.1
HEAD获得报文首部1.0/1.1
DELETE删除文件1.0/1.1
OPTIONS询问支持方法1.1
TRACE追踪路径1.1
CONNECT要求用隧道协议连接代理1.1
LINK建立和资源之间的联系1.0
UNLINE断开连接关系1.0

其中最为常见的请求方法为:GET POST

事实上,浏览器向服务器进行数据提交时,本质是前端通过form表单提交的,浏览器会自动将form表单中的内容转换为GET/POST的方法请求

例如在QQ的网址上会有登陆框,查看登陆框的源代码就会发现有form表单

image-20230808141948402

如果输入了账号密码之后点击了登陆按钮,浏览器就会将账号和密码根据指定的GET或者POST方法发送给服务器。

其中两者的区别有:

  1. GET方法会将获取到的数据作为参数直接通过url 传递,也就是说GET方法会在url 上直接显示出数据,格式为:http://ip:port/XXX/YY?name=value&name2=value2。会直接暴露出数据
  2. POST方法不是通过url 传递数据,而是直接向请求的正文里提交数据。也就是说参数会存在在正文里,服务器再从正文里提取参数
  3. 因为GET方法是再url中直接传递参数,所以参数不能太大
  4. POST在正文传递参数,所以可以参数很大

需要注意的是

虽然POST方法不会暴露数据,但是并不意味着就是安全的。私密 != 安全。

如果要谈到安全,那就必须要加密,加密内容属于https协议

http状态码

类别原因
1XXinformational - 信息性状态码接受的请求正在处理
2XXsuccess - 成功状态码请求正常处理完毕
3XXredirection - 重定向状态码需要进行附加操作以完成请求
4XXclient error - 客户端错误状态码服务器无法处理请求
5XXserver error - 服务端错误状态码服务器处理请求出错

其中最常见的就是 404 网页不存在

200 代表OK,404 Not Found,403 Forbiden,302 Redirect 重定向,504 Bad Gateway

http重定向

要实现重定向其实很简单,将状态码修改为307代表重定向,然后在正文里加入重定向的网址即可,这样向服务器请求后,服务器就会将处理的请求重定向到指定的网址

// 服务端处理的回调函数
bool func(const HttpRequest &req, HttpResponse &res)
{// 打印方便调试查看接收到的数据是否正确cout << "---------------http--------------" << endl;cout << req._inbuffer;cout << "_method: " << req._method << endl;cout << " _url: " << req._url << endl;cout << " _httpversion: " << req._httpversion << endl;cout << " _path: " << req._path << endl;cout << " _suffix: " << req._suffix << endl;cout << " _size: " << req._size << endl;cout << "---------------end---------------" << endl;// 状态行// string resline = "HTTP/1.1 200 OK\r\n";string resline = "HTTP/1.1 307 Temporary Redirect\r\n";// 响应报头// 需要注意正确的给客户端返回资源,图片是图片,网页是网页string rescontet = Util::suffixToDesc(req._suffix);// 添加资源长度到报头rescontet += "Content-Length: ";rescontet += to_string(req._size);rescontet += "\r\n";// 添加重定向rescontet += "Location: https://www.qq.com/\r\n";// 空行string resblank = "\r\n";// 响应正文string body;// 判断资源是否存在,不存在就返回错误状态码 - 404if (!Util::FileIsNo(req._path, &body)){Util::FileIsNo(errorhtml, &body);}// 写回响应的数据,后续要发送回客户端res._outbuffer += resline;res._outbuffer += rescontet;res._outbuffer += resblank;res._outbuffer += body;return true;
}

http常见Header

名称意义
Content-Type数据类型(text/html等)
Content-LengthBody的长度
Host客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上
User-Agent声明用户的操作系统和浏览器版本信息
referer当前页面是从哪个页面跳转过来的
location搭配3xx状态码使用, 告诉客户端接下来要去哪里访问 – 重定向
Cookie用于在客户端存储少量信息. 通常用于实现会话(session)的功能

实现简单业务逻辑

代码里涉及html代码,不详细讲解

由于服务器较弱,所以图片获取直接从网址获取,不从服务器读取

需要注意,一个网页看到的结果,可能是有多个资源组合而成,例如有网页,图片,视频等。所以要获取一张完整的网页效果需要浏览器发送多次请求,那么服务器就要根据请求的类型不同对响应正文处理的方式要指明Content-Type的类型。例如网页为“text/html”,jpg格式的图片为“image/jpeg”,不同的格式可自行搜索

判断格式的方法可以根据 url 中资源的后缀进行判断

以下代码均有注释:

Protocol.hpp

请求响应类

因为浏览器会自动处理收到的响应报文,所以不需要编写处理方法只需要将响应报文发送回浏览器即可

#pragma once#include <iostream>
#include <string>
#include <sstream>
#include "Util.hpp"using namespace std;// 定义分隔符
#define sep "\r\n"
#define default_root "./wwwroot"
#define home_page "index.html"
#define errorhtml "./wwwroot/404.html"// 请求
class HttpRequest
{
public:string _inbuffer; // 接收请求数据string _method; // 处理数据方法的名称string _url; // urlstring _httpversion; //  http协议版本string _path; // 查找资源的路径string _suffix;// 资源后缀int _size;//资源长度HttpRequest(){}// 处理收到的数据// 添加默认路径void parse(){// 拿到第一行string line = Util::GetOneLine(_inbuffer, sep);if(line.empty())return;cout << "line: " << line << endl;// 拿到第一行中的三个字段stringstream ss(line);ss >> _method >> _url >> _httpversion;// 添加默认路径_path = default_root;_path += _url;// 如果url为/ 则添加默认路径if(_path[_path.size() - 1] == '/')_path += home_page;// 获取资源的后缀auto pos = _path.rfind(".");if(pos == string::npos)_suffix = ".html";else_suffix = _path.substr(pos);// 获取到长度_size = Util::GetLen(_path);}};// 响应
class HttpResponse
{
public:string _outbuffer;
};

Util.hpp

工具类,将共有的方法定义同个类,方便调用

#pragma once#include <iostream>
#include <string>
#include <fstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>using namespace std;class Util
{
public:// 提取并删除首行// 读到的首行并不需要处理static string GetOneLine(string &inbuffer, const string &sep){auto pos = inbuffer.find(sep);if (pos == string::npos)return "";string sub = inbuffer.substr(0, pos);inbuffer.erase(0, sub.size() + sep.size());return sub;}// 判断请求的资源是否存在static bool FileIsNo(const string resource, string *out){ifstream in(resource);// 打开文件失败说明资源不存在if (!in.is_open())return false;string line;while (getline(in, line))*out += line;in.close();return true;}// 根据后缀指明响应报头类型static string suffixToDesc(const string &suffix){string st = "Content-Type: ";if (suffix == ".html")st += "text/html";else if (suffix == ".jpg")st += "image/jpeg";st += "\r\n";return st;}// 获取资源的长度static int GetLen(const string &path){struct stat s;int n = stat(path.c_str(), &s);if(n == 0)return s.st_size;return -1;}
};

Server.hpp

#pragma once#include "Protocol.hpp"
#include <sys/types.h>
#include <sys/socket.h>
#include <cstring>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
#include <sys/wait.h>
#include <unistd.h>using func_t = function<bool(const HttpRequest &, HttpResponse &)>;class Server
{
public:Server(func_t func, uint16_t &port): _port(port), _func(func){}void Init(){// 创建负责监听的套接字 面向字节流_listenSock = socket(AF_INET, SOCK_STREAM, 0);if (_listenSock < 0)exit(1);// 绑定网络信息struct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(_port);local.sin_addr.s_addr = INADDR_ANY;if (bind(_listenSock, (struct sockaddr *)&local, sizeof(local)) < 0)exit(3);// 设置socket为监听状态if (listen(_listenSock, 5) < 0)exit(4);}// 服务端读取处理请求方法void HttpHandler(int sock){// 确保读到完整的http请求char buffer[4096];size_t n = recv(sock, buffer, sizeof(buffer) - 1, 0);HttpRequest req;HttpResponse res;if (n > 0){buffer[n] = 0;req._inbuffer = buffer;// 处理读到的数据req.parse();// 调用回调方法反序列化请求并得到响应结果和序列化响应结果_func(req, res);// 发回客户端send(sock, res._outbuffer.c_str(), res._outbuffer.size(), 0);}}void start(){while (1){// server获取建立新连接struct sockaddr_in peer;memset(&peer, 0, sizeof(peer));socklen_t len = sizeof(peer);// 创建通信的套接字// accept的返回值才是真正用于通信的套接字_sock = accept(_listenSock, (struct sockaddr *)&peer, &len);if (_sock < 0)continue;cout << "sock: " << _sock << endl;// 利用多进程实现pid_t id = fork();if (id == 0) // child{close(_listenSock);// 调用方法包括读取、反序列化、计算、序列化、发送HttpHandler(_sock);close(_sock);exit(0);}close(_sock);// fatherpid_t ret = waitpid(id, nullptr, 0);}}private:int _listenSock; // 负责监听的套接字int _sock;       // 通信的套接字uint16_t _port;  // 端口号func_t _func;
};

Server.cc

#include "Server.hpp"
#include <memory>// 输出命令错误函数
void Usage(string proc)
{cout << "Usage:\n\t" << proc << " local_ip local_port\n\n";
}// 服务端处理的回调函数
bool func(const HttpRequest &req, HttpResponse &res)
{// 打印方便调试查看接收到的数据是否正确cout << "---------------http--------------" << endl;cout << req._inbuffer;cout << "_method: " << req._method << endl;cout << " _url: " << req._url << endl;cout << " _httpversion: " << req._httpversion << endl;cout << " _path: " << req._path << endl;cout << " _suffix: " << req._suffix << endl;cout << " _size: " << req._size << endl;cout << "---------------end---------------" << endl;// 状态行string resline = "HTTP/1.1 200 OK\r\n";// string resline = "HTTP/1.1 307 Temporary Redirect\r\n";// 响应报头// 需要注意正确的给客户端返回资源,图片是图片,网页是网页string rescontet = Util::suffixToDesc(req._suffix);// 添加资源长度到报头rescontet += "Content-Length: ";rescontet += to_string(req._size);rescontet += "\r\n";// // 添加重定向// rescontet += "Location: https://www.qq.com/\r\n";// 空行string resblank = "\r\n";// 响应正文string body;// 判断资源是否存在,不存在就返回错误状态码 - 404if (!Util::FileIsNo(req._path, &body)){Util::FileIsNo(errorhtml, &body);}// 写回响应的数据,后续要发送回客户端res._outbuffer += resline;res._outbuffer += rescontet;res._outbuffer += resblank;res._outbuffer += body;return true;
}int main(int argc, char *argv[])
{// 启动服务端不需要指定IPif (argc != 2){Usage(argv[0]);exit(1);}uint16_t port = atoi(argv[1]);unique_ptr<Server> server(new Server(func, port));// 服务端初始化server->Init();// 服务端启动server->start();return 0;
}

效果

在此就不写出html的文件了,看着效果能够实现即可

可以看到浏览器向服务器发送请求,服务器返回响应,响应里就包括了自己编写的html文件,所以浏览器处理后就显示出了自己的网页

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

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

相关文章

策略模式实战应用

场景 假设做了个卖课网站&#xff0c;会员等级分为月vip、年vip、终生vip&#xff0c;每个等级买课的优惠力度不一样&#xff0c;传统的写法肯定是一堆的 if-else&#xff0c;现在使用策略模式写出代码实现 代码实现 策略模式的核心思想就是对扩展开放&#xff0c;对修改关闭…

网络安全渗透测试之靶场训练

NWES: 7月26号武汉地震检测中心遭受境外具有政府背景的黑客组织和不法分子的网络攻击。 目前网络攻击主要来自以下几种方式: DDOS&#xff1a;分布式拒绝服务攻击。通过制造大量无用的请求向目标服务器发起访问&#xff0c;使其因短时间内无法处理大量请求而陷入瘫痪。主要针对…

实时通信应用的开发:Vue.js、Spring Boot 和 WebSocket 整合实践

目录 1. 什么是webSocket 2. webSocket可以用来做什么? 3. webSocket协议 4. 服务器端 5. 客户端 6. 测试通讯 1. 什么是webSocket WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单&#xff0c;允许服务…

【LeetCode】870 . 优势洗牌

870 . 优势洗牌 方法&#xff1a;贪心 思路 这道题的思想类似于 “田忌赛马” &#xff0c;把 nums1 当成是田忌的马&#xff0c;nums2 当成是齐威王的马。 讨论田忌的下等马&#xff08;nums1 的最小值&#xff09;&#xff1a; 如果它能比过齐威王的下等马&#xff08;nums…

AD域机器KMS自动激活

1、打开AD域控&#xff0c;点击DNS管理 2、创建其它记录 3、选择服务位置 SRV 4、输入相关信息 服务&#xff1a;_VLMCS协议&#xff1a;_TCP权重&#xff1a;100端口号&#xff1a;1688KMS服务器地址&#xff1a;10.3.0.211 5、成功&#xff0c;这时域内主机重启后&#xff0…

第48节:cesium 面交集计算(含源码+视频)

结果示例: 完整源码: <template><div class="viewer"><vc-viewer @ready="ready" :logo="false"><vc-navigation

postgresql之内存池-GenerationContext

创建GenerationContext MemoryContext GenerationContextCreate(MemoryContext parent,const char *name,Size blockSize) {GenerationContext *set; ...set (GenerationContext *) malloc(MAXALIGN(sizeof(GenerationContext))); .../* Fill in GenerationContext-specific …

Angular安全专辑 —— CSP防止XSS攻击

什么是 CSP&#xff08;Content Security Policy&#xff09; CSP&#xff08;Content Security Policy&#xff09;是一种Web安全策略&#xff0c;用于减轻和防止跨站脚本攻击&#xff08;XSS&#xff09;等安全漏洞。它通过允许网站管理员定义哪些资源可以加载到网页中&#…

计算机网络(8) --- IP与IP协议

计算机网络&#xff08;7&#xff09; --- UDP协议和TCP协议_哈里沃克的博客-CSDN博客UDP协议和TCP协议https://blog.csdn.net/m0_63488627/article/details/132125374?spm1001.2014.3001.5501 目录 1.IP与IP协议 IP作用 协议​编辑 2.网段划分 DHCP划分 CIDR划分 特殊…

旷视科技AIoT软硬一体化走向深处,生态和大模型成为“两翼”?

齐奏AI交响曲的当下&#xff0c;赛道玩家各自精彩。其中&#xff0c;被称作AI四小龙的商汤科技、云从科技、依图科技、旷视科技已成长为业内标杆&#xff0c;并积极追赶新浪潮。无论是涌向二级市场还是布局最新风口大模型&#xff0c;AI四小龙谁都不甘其后。 以深耕AIoT软硬一…

大语言模型之三 InstructGPT训练过程

大语言模型 GPT历史文章中简介的大语言模型的的发展史&#xff0c;并且简要介绍了大语言模型的训练过程&#xff0c;本篇文章详细阐述训练的细节和相关的算法。 2020年后全球互联网大厂、AI创业公司研发了不少AI超大模型&#xff08;百亿甚至千亿参数&#xff09;&#xff0c;…

人大金仓三大兼容:Oracle迁移无忧

企业级应用早期的架构模式是C/S&#xff08;Client/Server&#xff09;模式&#xff0c;Client做人机交互逻辑的呈现&#xff0c;Sever做业务计算逻辑的实现。这就类似餐馆的运作模式&#xff0c;Client是前台的服务员提供点菜和上菜服务&#xff0c;而Server则是后厨完成菜品的…

【论文阅读】基于深度学习的时序异常检测——TransAD

系列文章链接 数据解读参考&#xff1a;数据基础&#xff1a;多维时序数据集简介 论文一&#xff1a;2022 Anomaly Transformer&#xff1a;异常分数预测 论文二&#xff1a;2022 TransAD&#xff1a;异常分数预测 论文三&#xff1a;2023 TimesNet&#xff1a;基于卷积的多任务…

角角の Qt学习笔记(一)

目录 一、解决在创建新项目时遇到的几个问题 二、信号和槽&#xff08;非自定义&#xff09; 三、调用 UI 中的元素&#xff08;比如按钮&#xff09; 一、解决在创建新项目时遇到的几个问题 在新建项目时&#xff0c;我选择的构建系统为CMake。然后勾选了Generate form&…

各地区-各行业法人单位、区划数63个指标(2010-2022年)

一、数据介绍 数据名称&#xff1a;各地区-各行业法人单位、区划数63个指标 数据年份&#xff1a;2010-2022年&#xff08;法人单位至2021年&#xff09; 数据样本&#xff1a;404条 数据来源&#xff1a;自我整理 二、指标说明 行政区划代码 地区 长江经济带 经度 纬…

CAP理论与MongoDB一致性,可用性的一些思考

正文 大约在五六年前&#xff0c;第一次接触到了当时已经是hot topic的NoSql。不过那个时候学的用的都是mysql&#xff0c;Nosql对于我而言还是新事物&#xff0c;并没有真正使用&#xff0c;只是不明觉厉。但是印象深刻的是这么一张图片&#xff08;后来google到图片来自这里&…

Java实现对称加密(DES,AES)快速入门示例

对称加密是使用相同的密码进行加密和解密&#xff0c; 对称加密实现简单&#xff0c;安全性相比非对称加密较弱&#xff0c; 常用的对称加密算法有 DES&#xff0c;AES以及PDE等&#xff0c;关于对称加密相关概念参考&#xff1a; 对称加密、非对称加密深度解析 本篇介绍Java的…

python——案例17:判断某年是否是闰年

案例17&#xff1a;判断某年是否是闰年 判断依据&#xff1a;闰年就是能被400整除&#xff0c;或者能被4整除的年份numint(input(输入年份&#xff1a;))if num%1000: if num%4000: #整百年份的判断print("%s年是闰年"%num) #…

设计模式行为型——状态模式

目录 状态模式的定义 状态模式的实现 状态模式角色 状态模式类图 状态模式举例 状态模式代码实现 状态模式的特点 优点 缺点 使用场景 注意事项 实际应用 在软件开发过程中&#xff0c;应用程序中的部分对象可能会根据不同的情况做出不同的行为&#xff0c;把这种对…

flutter开发实战-实现marquee根据文本长度显示文本跑马灯效果

flutter开发实战-实现marquee文本跑马灯效果 最近开发过程中需要marquee文本跑马灯效果&#xff0c;这里使用到了flutter的插件marquee 效果图如下 一、marquee 1.1 引入marquee 在pubspec.yaml中引入marquee # 跑马灯效果marquee: ^2.2.31.2 marquee使用 marquee使用也是…