HTTP详解(用C++来实现一个简单的http协议,附带一个浏览器插件源码)

时间:2024-03-11 14:50:08

从C++角度来理解http请求协议

这里不会详细的介绍http里面的各个字段只会给大家介绍从C++ windows socket角度来理解http(会有很多经验分享哦 欢迎来辩 thanks)

目录

http简介

HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。。
HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。
HTTP是通过明文来进行通信的所以这里分为 请求端(客户端:可以是浏览器,exe程序 甚至是安卓的应用程序或者另一个服务器程序)和响应端(服务端:可以是阿帕奇,ngx至于服务器上的语言就可以是java php c#或者node,C++等)

http请求头

accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
accept-encoding: gzip, deflate, br
accept-language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,tr;q=0.6
cache-control: max-age=0
cookie: xxx
referer: https://home.cnblogs.com/u/huihuishijie/
sec-fetch-dest: document
sec-fetch-mode: navigate
sec-fetch-site: same-origin
sec-fetch-user: ?1
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36

字段说明: cookie代表的是cookie
cache-control代表的是缓存的信息,
至于剩下的字段我们可以看这篇博文:https://www.cnblogs.com/JamelAr/p/10825477.html

http响应头

content-encoding: gzip
content-type: text/html; charset=utf-8
date: Sun, 18 Oct 2020 14:41:33 GMT
status: 200 
strict-transport-security: max-age=2592000; includeSubDomains; preload
vary: Accept-Encoding

字段说明: status代表的是服务器状态码
详细的可以查看博文:https://www.cnblogs.com/wangyang108/p/5755525.html







用列子来说明(windows socket)

例子的环境说明:
操作系统:windows10
编辑器:VS2017
客户端:谷歌浏览器(请求端)

文章源码下载

完整源码下载:httpClass.rar

完整目录截图

完整目录截图

目录说明:
  • classForBase 放一些基本类的文件夹

    * helpClass  http请求的帮助类
    * oMap       一个线性的table类
    * server     一个简易的服务器封装类
    
  • 404.html 当页面找不到的时候返回的页面

  • httpClass.cpp 入口函数的文件 main函数

  • index.html 当访问我们的浏览器页面的时候返回的html页面

  • pch 公共头文件或者公共方法的实现文件

  • test.css 一个空css文件

  • test.js 这个文件封装了一个简易的浏览器插件思路后面会详细的说明

流程说明

  • 编写预览的html文件

  • 编写基本的帮助类和线性table类

  • 编写服务端类

  • 编写入口函数

  • 编写测试浏览器插件js 编写浏览器插件相关方法

helpClass源码

这里我们先忽略winapi的相关函数 与 winsocket的函数 我们这里就只是说一个流程
首先看方法methodGetHandle

void helpClass::methodGetHandle(SOCKET & s, string request, oMap<string, string>getMap) {
	//响应头map
	oMap<string, string>reqMap;
	//设置日期
	reqMap["Date"] = getTime();
	//获取文件服务器地址
	string filePath = getFileUrl(getMap["Host"], "GET", getMap);
	//获取文件信息 如果是等于1那么就是一个ajax请求
	vector<string> filePathInfo = helpClass::split(filePath, ".");

	//定义响应内容
	string content;
	int status=helpClass::readFile(filePath, content);
	if (status == 404) {
		status = helpClass::readFile("404.html", content);
	}
	string contentType = "";
	//设置响应头
	reqMap["content-type"] = contentType + getMINItype(filePath);
	int len = content.length();
	char bufLen[4] = {0};
	_itoa_s(len, bufLen, 10);
	reqMap["Charset"] = getFileCharset(filePath);
	reqMap["content-length"] =bufLen;
	reqMap["cache-control"] = "private, must-revalidate";
	reqMap["server"] = "yServer";
	reqMap["X-Content-Type-Options"] = "nosniff";
	reqMap["X-Frame-Options"] = "SameOrigin";
	reqMap["x-xss-protection"] = "1; mode=block";
	if (filePathInfo.size() == 1 || (filePathInfo.size() == 2 && filePathInfo[0] == "")) {
		reqMap["content-type"] = "text/plain";
		reqMap["content-length"] = 1;
		content = "";
		::getMethodInfo(getMap, reqMap, content);
	}
	string getReqHead = getResponseHead(request, status, "OK", reqMap);
	
	getReqHead = getReqHead + "\r\n" + content;
	send(s, getReqHead.c_str(), getReqHead.length(), 0);
	//关闭套接字 让套接字不一直都访问
	closesocket(s);
}

上面的方法是一个简易的winsocket处理http get请求的响应方法:

首先我们来看request参数 这里我就直接用vs2017的断点截图了

request请求头的截图信息
我们可以看到request在这里是C++的一个字符串
那么我们如果要实现一个比较标准的C++字符串我们就应该按照http的相关协议来完成这个请求头的各个字段的实现(当然我们也可以不按照标准的http协议来实现里面各个请求头毕竟请求头是告诉服务器你应该做一些什么)

getMap这个参数就是我们将request字符串转化为一个比较简陋的线性table方便我们操作
下面我们来看这个方法的响应了

就是服务端给客户端发送响应
如果你正在按照我的这个流程打上了断点,那么你的浏览器请求的地址应该一直是在转圈的。这是因为服务器没有返回
** 既然我们要响应一个请求:**

  • 第一步我们先拼装响应头

    * 这里我们用的是一个reqMap变量(一个自己实现的比较简陋的线性table类型)来方便我们操作  
    
    * 这里我们先将响应头的各个数据拼装起来  
    
  • 第二步我们就要去根据请求头里面的host参数或者一些其他的参数来获取文件内容

  • 第三步然后我们用winsocket的套接字丢给我们的客户端(浏览器)

这里我们来看下我们的完整发送数据

可以看到我们丢给套接字发送给客户端的完整内容就是这样的 响应头+"\n\r"+内容
内容就是我们通过windowsapi的文件操作方法读取的,(PS:这里如果我们想进行一些加密我们就可以用aes将发送的内容通过唯一的秘钥进行加密 然后通过客户端的比较完整的js进行aes解密。html也是可以加密的哦 嘿嘿)
如果你细心的调试到这一步了,那么可能你会对http有一个新的认识。好了这里就暂时告一段落了。
如果有写的不好的欢迎留言我改正 嘿嘿嘿
具体的源码:自己下载调试哦 完整源码下载:httpClass.rar







http常见的调试工具

fiddler中的http简易介绍

可以看到此应用完整截图

fiddler软件完整界面截图

点击到原始数据内容查看:

原始数据查看截图
这里我们可以看到我们通过C++返回的协议被抓获了这里发送的数据就是我们自己拼接的套接字数据。

然后点击文本视图

文本视图截图
可以看到这里就是我们拼接的文件内容 所以看到这里了 是不是对http又有了一些新的认识呀。
好了这里我们就不详细的介绍fiddler的使用了 下面我们看另一个应用 也是前端开发者最喜欢用的

谷歌浏览器f12中的http介绍

这里是截的F12的network(如果这里没有任何请求 我们在F12打开的情况下刷新一下页面)

一个截图

我们这里看到第一个请求的截图

第一个其你去的截图
这里我们可以看到的是请求头和响应头我们都知道这两个头的使用了 那么我们切换到response response
可以看到response就是我们的内容文本
所以看到这里了我们是不是完整的走了一个http的流程呀?
比较好说明http流程的应用我们就看着两个了







http浏览器插件

由C++列子开发一种本地服务形式的浏览器插件(Clodop等之类的插件)

emmm开头还是我们的源码连接嘿嘿 完整源码下载:httpClass.rar

插件原理:

  • 第一步我们先用C++构建一个本地服务器(需要用户安装这个exe并且启动 至于如何设置exe开机就启动我们这里就不说了。当然也可以用windowsapi的服务api来控制启动这个exe)
  • 第二步构建一个js工具
  • 第三步使用的页面通过script标签的src引入我们C++本地服务输出的js文件
  • 第四步使用js的api方法然后js的api方法通过http去请求C++本地服务
    * 然后C++本地服务调用windowsapi 就可以通过js调用一些js无法完成的功能了
    * 比如获取用户本地文件夹信息 就可以通过exe获取到文件夹信息返回给js的api的回调函数
  • 第五步实现C++的windowsapi调用

这里我们实现的插件功能是js调用本地windows电脑上的计算器,通过此原理服务端的构建可以不止是C++,(也可以是C#,php,或者内置了C++插件的nodejs,当然这里不能少java,万能的C当然也是可以的 嘿嘿)这里由于楼主通过C++实现了一个简易的http协议,所以就直接用这份代码了,不然我绝对用世界上最好的语言。

C++服务器完善

处理get请求参数的方法
由于时间关系我这里就没有去按照标准的规则编写了 就写死了一个规则 通过传入的参数 调用winExec 即调用cmd来运行一些命令
这里可以直接下载源码来进行调试完整源码下载:httpClass.rar

编写js文件

其实根据服务器构建的方法就可以看出来了 这里我们只需要请求一个带参数的get请求就可以调用cmd命令行了

这里我们用原生js实现了一个简易的get请求可以看到我们定义了一个全局对象YCon对象
此对象提供方法 openExe 和一个回调函数

引入js文件

引入我们编写的这个js文件到需要此功能的项目中这样我们就可以通过调用YCon.openExe的方法打开部分本地应用了

运行效果

这个就是此插件运行的效果可以用浏览器的控制台调用windows的部分本地应用







结束语

如果你花了二三十分钟看了这篇文章,希望你有所收获。欢迎留言指正。

曾经天很蓝,草很绿。时光荏苒,物是人非。不变的是我们的那一颗初心,第一篇技术分享结束了。