news 2026/8/31 15:15:26

HTTP协议基础知识梳理、实现与简单应用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HTTP协议基础知识梳理、实现与简单应用

HTTP基础知识


一、网址的构成


1.协议

告诉浏览器用户用什么规则访问。

2.域名

域名通过域名解析转变为ip地址,对于对外提供服务的Web服务器默认使用80(HTTP)和443(HTTPS)端口,如果没写端口号,访问http://会自动补上:80。

3.URL统一资源定位符

所有网络上的资源都可以被唯一的一个字符串标识,也就是URL(统一资源定位符)

4.文件路径

浏览器不可能把所有网站的所有资源都存起来,一个网站的资源几种存放在服务器的指定的目录下(web根目录),而网址中显示的文件路径是客户端当前访问资源对应的路径。

5.冲突字符的处理

网络行为包括获取数据与传输数据,而传输数据如果采用的是时可能因为

域名通过域名解析变为ip地址


二、HTTP协议格式

输入网址按下enter本质是向服务器发送了请求,服务器处理后发送对应的网页资源,这才实现了网页页面的跳转。下面详细介绍HTTP请求和响应的协议格式。


1.请求协议

HTTP请求协议格式如上图所示,行间使用"\r\n"进行分隔,而行内使用空格分开(附:属性键值对的“Key:”后面也要加一空格)下面对各部分进行说明。

(1)请求行

请求方法一般用GET和POST这两种方法,后文会展开来讲,空一格后写URL,接着是协议版本,客户端和服务器的版本可能不同导致支持的功能有所差异(后文解释),所以需要带上。

(2)请求属性

请求属性以键值对格式填写,实际上也的确使用键值对做查找匹配。下面为常见属性:

(3)空行

空出一行用于区分报头和报文。服务端读到空行时说明报头已完整读取,而报头里包含内容请求正文长度这一属性,这两个特点共同保证报文的完整性。因此,一个请求至少要有请求行和空行。

(4)请求正文

即用户要上传的数据。


2.响应协议

响应协议和请求协议类似,仅状态行有所不同,也有协议版本,而状态码和状态码描述用于表述响应状态(如404 Not Found)


3.协议细节


(1)http方法

GET方法

使用把要上传的数据放到url里面

POST方法

提交的参数是放在请求正文内的,

两种方法的使用时机

get方法的参数个数有限制 另外参数在搜索的时候会回显到网址框那里不安全

post方法相对安全,但不加密也是不安全的,本质是不直接泄漏用户的信息。


(2)表单

无论采用上述哪一种方法,用户的数据都是通过前端的表单提交的,如下面代码:

<form action="/" method="get"> name: <input type="text" name="name"><br> passwd: <input type="text" name="passwd"><br> <input type="submit" value="提交"> </form>

效果如下图(emm乱码那是提交按键):

输入并提交后浏览器上传数据如下:

http://182.254.173.195:8080/?name=dasdsa&passwd=dadasdsasdasda

表单还可以有其它作用,比如在上文表单代码示例中,如果action指向一个可执行程序时,服务器收到请求后,会创建子进程执行该程序,并将表单数据通过环境变量或标准输入传递给它,实现动态处理(如用户注册、数据录入)。


(3)状态码

响应报头中的状态码向客户端说明处理状态,类似于错误码。如常见的404就是代表无法找到页面的状态码。

下面讲下3开头的状态码,也就是重定向相关的状态码。

301(永久重定向):资源永久迁移到新 URL,浏览器会缓存跳转结果,下次直接访问新地址(适用于域名更换、资源永久搬家)。

302(临时重定向):资源暂时跳转,浏览器不会缓存,每次仍然访问原 URL(适用于临时维护、活动页跳转)。


(4)常见的报头

Content-Type: 数据类型(text/html等)

Content-Length: Body的长度

Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;

User-Agent: 声明用户的操作系统和浏览器版本信息,可用于反爬。

referer: 当前页面是从哪个页面跳转过来的;可配合浏览器的前进和后退页面的功能实现

location: 搭配3xx状态码使用, 告诉客户端接下来要去哪里访问;

Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能;


(5)长短连接

一个网页页面通常包含多个元素,而每一个元素就是一个资源。如果服务器和浏览器对每个资源都做请求和响应会非常耗费时间。

一次请求响应一个资源,随后关闭连接,就是短链接,http1.0默认使用短链接,如果要使用长连接则Connection属性要设置为keep-alive。

建立链接后一次性发送或返回多个http的请求或响应的过程就是长链接。http1.1默认使用长链接,也可使用短连接。

之所以一开始要交换版本信息,就是为了防止通信双方中有一方只支持 HTTP/1.0连接自动降级为短连接模式。


(6)Cookie(缓存)

http本身默认是无状态的,也就是没有缓存。

在网页注册账户后,浏览器会帮忙保存cookie,也就是你的账号密码,此后用户登录该网页时,浏览器向网页服务器发送请求会自动带上账密,从而跳过到了登陆环节。

cookie有文件级别也有内存级别。顾名思义内存级cookie是保存在浏览器的内存中的,关闭浏览器后下次再次打开并登录网页需要重新输入。而文件级别的cookie可将cookie放在浏览器文件夹中长期保留。

在服务端的响应字段中加入Set-Cookie属性从而设立一个cookie,见下面参考代码:

response+= "Set-Cookie: ussrname=zzs&&passwd=12345\r\n";//缓存设置

(7)cookie的安全问题
1.可能被盗取

cookie被外部拿到本身不可避免,但sessionid由服务器统一管理,可随时销毁,所以异地登录可要求认证,也就是重新设置sessionid。

2.个人私有信息泄漏

登陆账号也是上传数据的过程,也就是密码可能出现在URL中。

应对方法:不再直接将密码作为cookie而是由服务器生成的sessionid传给浏览器,下次通过id匹配登录,服务器可将sessionid交由redis数据库管理。黑客虽然仍可拿取cookie,但这时候回显的只是id,真正的密码由网站管理,使得私人信息不被泄漏。


HTTP的实现


实现目的

结合上述HTTP知识,利用TCP实现一HTTP服务器,并编写简单网页,打通前后端隔阂,理解HTTP的应用。


实现思路

和TCP的封装及应用类似,首先利用socket接口建立连接,然后基于TCP协议进行数据传输。而对于HTTP而言,难点在于服务端需要遵守协议规范,具有正确读取并解析请求、并返回正确响应的功能,此外还涉及到网页代码和文件操作相关知识,这里不对这两点以及服务器的运作方式多做深挖,直接采用多线程的方式接收请求,线程函数负责处理请求并返回响应。


反序列化

对请求做反序列化,和以往需要拆解字符串本身不同,请求本身已规范使用"\r\n"作为分隔符,这里的任务是把各行拆开放入数组,并对请求行做拆解赋值给成员变量。

具体代码如下:

std::string linesep = "\r\n";//行分隔符 std::string wordsep = "\0";//行内分隔符 struct thread_info//线程信息 { HttpServer *hsp;//服务器指针,传this要用 int fd; }; class Request { public: Request() {} void deserialization(std::string target)//对请求做反序列化 { // 按行读取 std::string line; while (true) { size_t pos = target.find(linesep); std::string temp = target.substr(0, pos); if (temp.empty()) { break;//空行被找到 } header.push_back(temp); target.erase(0, pos + linesep.size());//将缓冲区内对应的字符删除,避免影响后续存储的请求。 } // 找到空行后剩下的就是请求正文,直接赋值 text = target; } void Parse() { std::stringstream ss(header[0]); //流式切割,获取请求头信息,url最为重要,用于定位用户需要访问的资源路径 ss >> method >> url >> http_version; } std::string GetUrl() { return url; } private: //用于存放请求头和请求报头内容的数组 std::vector<std::string> header; //请求正文 std::string text; //请求行信息 std::string method; std::string url; std::string http_version; };

负责处理请求的线程函数

这里直接省略完整代码,从线程函数开始讲解,完整代码见本章末。

接收到的参数是封装好的线程信息,包括服务器指针和sockfd.

struct thread_info//线程信息 { HttpServer *hsp;//服务器指针,传this要用 int fd; };

Run方法负责接收请求和发送响应,而处理并构建响应由handler方法处理。

static void *Run(void *argv) { // 接收 处理并得到响应(handler) 发送 thread_info *info = (thread_info *)argv; pthread_detach(pthread_self()); char buf[10240] = {0}; int n = recv(info->fd, buf, sizeof(buf) - 1, 0); // 接收http请求 if (n > 0) { std::string request = buf; std::string sendmessage = info->hsp->handler(request); send(info->fd, sendmessage.c_str(), sendmessage.size(), 0); delete info; } else if (n == 0) { LOG(INFO, "Client exit"); delete info; } else { LOG(FATAL, "recv fail"); delete info; } return nullptr; }

handler负责拆解请求并判断用户输入的路径,根据路径获取对应的资源(Getcontent方法实现)用于填充响应正文,至于响应头,主要是检查资源类型补充的Content_Type属性,响应正文的长度Content-Length,以及缓存设置Set-Cookie,然后返回整个响应。content_type对应的unordermap直接在构造函数中硬编码。

std::string Getcontent(std::string &sourcepath) { // 图片文件需要用读取为二进制方式读取 std::ifstream in(sourcepath, std::ios::binary); if (!in.is_open()) { return ""; // 文件打开失败,返回空字符串 } in.seekg(0, std::ios::end); size_t size = in.tellg(); in.seekg(0, std::ios::beg); std::string content(size, '\0'); std::cout<<"size:"<<size<<std::endl; in.read(&content[0], size); in.close(); return content; } std::string CheckType(std::string &url){ size_t pos=url.rfind('.'); //如果没有找到默认是网页资源 if (pos == std::string::npos) { return content_type_[".html"]; } std::string type=url.substr(pos); auto it =content_type_.find(type); if(it==content_type_.end()){ return content_type_[".html"]; } else{ return content_type_[type]; } } std::string handler(const std::string &recvmessage) { // 负责处理请求,判断路径,获取资源(Getcontent方法实现),返回响应 //构建请求类,做反序列化 Request rq; rq.deserialization(recvmessage); rq.Parse();//获取请求行各参数信息 rq.DebugPrint();//博客中省略debugprint // 对资源路径做判断 //注意一般用户不会吧web根目录写上来,服务器在这里直接帮忙添加 std::string sourcepath; std::string url = rq.GetUrl(); bool redirect = false; if (url == "/" + homepage || url == "/")//如果用户给的是/或本来就是首页,直接把首页返回给浏览器(不可能把整个根目录下所有资源给用户) { sourcepath = wwwroot + "/" + homepage;//首页路径 } else if (url == "/oldpakage.html")//若该网址搬迁,自动跳转到新网站中 { sourcepath = wwwroot + "/" + "newpakage.html"; redirect = true; } else { sourcepath = wwwroot + url;//正常资源路径正常处理 } std::string content = Getcontent(sourcepath);//获得响应正文 std::string response_line;// if (content.empty()) { //如果内容为空,说明文件路径错误,给用户返回404页面 std::string errpath = wwwroot + '/' + "notfound.html"; content = Getcontent(errpath); response_line = "HTTP/1.0 404 Notfound\r\n";//响应行直接硬编码,后文相同 } else if (redirect)//如果前文发现用户要访问旧网址,响应行给302状态码和描述 { response_line = "HTTP/1.0 302 Redirect\r\n"; } else { response_line = "HTTP/1.0 200 OK\r\n"; } std::cout << "content:" << content << std::endl; //检查用户要访问的资源类型并构建Content_Type属性 std::string ContentType="Content_Type: "+CheckType(url)+"\r\n"; std::string blank_line = "\r\n"; //组装响应 std::string response; response += response_line; response+=ContentType; response += "Content-Length: " + std::to_string(content.size()) + "\r\n"; response += "Connection: close\r\n"; response+= "Set-Cookie: ussrname=zzs&&passwd=12345\r\n";//缓存设置 //检查重定向 if (redirect) { response += "Location: /newpakage\r\n"; } response += blank_line; response += content; return response; }

html文件这里省略,如果要查看完整代码和文件详见:

HTTP的封装与应用https://gitee.com/zhang-zheshun/linux-learning-repository/tree/master/net_learning/HTTP

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/31 15:15:09

机器学习系统学习路线:从数学基础到实战项目

很多人在学习机器学习时&#xff0c;都会陷入一个相似的困境&#xff1a;收藏夹里存了几十个教程链接&#xff0c;网盘里躺着好几个G的视频资源&#xff0c;今天看一集线性代数&#xff0c;明天刷一个Python语法&#xff0c;后天又去啃一会儿决策树。碎片信息越攒越多&#xff…

作者头像 李华
网站建设 2026/8/31 15:15:00

基于Qt的PID调试上位机:实时曲线与参数整定实战

简介&#xff1a;这是一份面向自动化控制初学者与嵌入式/工业软件开发者的Qt可视化PID调试工具&#xff0c;解决PID参数整定缺乏直观反馈、调试过程依赖命令行或MATLAB的痛点&#xff0c;适用于电机控制、温控系统、机器人姿态调节等典型闭环控制场景。资源共7个文件&#xff0…

作者头像 李华
网站建设 2026/8/31 15:14:32

MATLAB优化算法工具箱核心函数详解与混合优化实战

在实际的工程计算和科研项目中&#xff0c;很多问题最终都会落到同一个数学任务上&#xff1a;在给定资源、成本、工艺等约束条件下&#xff0c;让利润最大、能耗最低&#xff0c;或者让某个系统响应与期望目标之间的误差最小。这类问题在数学上统一称为优化问题。很多新手一开…

作者头像 李华
网站建设 2026/8/31 15:13:34

C#实现Modbus TCP上位机通讯:协议解析与实战源码

简介&#xff1a;这是一套面向工业自动化工程师、物联网开发者及高校学生的Modbus TCP上位机开发实践资源&#xff0c;聚焦PLC与上位机通信核心场景&#xff0c;解决协议解析、实时数据读写、设备状态监控与异常报警等典型工程问题。资源包含56个文件&#xff0c;以8个核心C#源…

作者头像 李华
网站建设 2026/8/31 15:12:16

Agent评测场景自动化:从OpenAPI工具规格到可执行验证的完整实践

在实际的 LLM Agent 工程落地中&#xff0c;评测场景的供给速度往往落后于工具数量的增长速度。Agent Seer 这一类思路的核心&#xff0c;是把工具规格&#xff08;Tool Specification&#xff09;当作评测场景的原料&#xff1a;通过解析 OpenAPI、JSON Schema 或函数签名&…

作者头像 李华
网站建设 2026/8/31 15:08:27

springboot某饭店点菜小程序94858-计算机课程设计、毕业设计

前言 博主介绍&#xff1a;一线全栈工程师&#xff0c;毕设实战引路人。技术栈覆盖Java、Python、C#、PHP、Node.js及UniApp跨端开发&#xff0c;擅长多语言项目落地与架构设计。持续分享毕设源码、开题报告、技术选型心得与职场踩坑经验。用工程化思维写代码&#xff0c;帮你…

作者头像 李华