HTTP詳解(用C++來實現一個簡單的http協議,附帶一個瀏覽器插件源碼)


從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的部分本地應用







結束語

如果你花了二三十分鍾看了這篇文章,希望你有所收獲。歡迎留言指正。

曾經天很藍,草很綠。時光荏苒,物是人非。不變的是我們的那一顆初心,第一篇技術分享結束了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM