需要云服務(wù)器等云產(chǎn)品來學(xué)習(xí)Linux的同學(xué)可以移步/-->騰訊云<--/-->阿里云<--/-->華為云<--/官網(wǎng),輕量型云服務(wù)器低至112元/年,新用戶首次下單享超低折扣。
??目錄
一、http協(xié)議
1、http協(xié)議的介紹
2、URL的組成
3、urlencode和urldecode
二、http的請求方法、狀態(tài)碼及狀態(tài)碼描述、常見的響應(yīng)報頭
1、http請求方法
2、http狀態(tài)碼及狀態(tài)碼描述?
3、http常見的響應(yīng)報頭
三、http協(xié)議客戶端和服務(wù)器的通信過程
1、如何保證請求和響應(yīng)被應(yīng)用層完整的讀取了?
2、請求和響應(yīng)如何做到序列化和反序列化
3、客戶端和服務(wù)器通信的全過程?
4、獲取響應(yīng)正文的長度
四、http長連接
五、http會話保持(客戶端Cookie,服務(wù)器session)
六、http相關(guān)工具
本文http協(xié)議詳細代碼可參照博主gitee。
一、http協(xié)議
1、http協(xié)議的介紹
????????http屬于應(yīng)用層協(xié)議。雖然應(yīng)用層協(xié)議是程序員自己定的,但實際上, 已經(jīng)有前輩們定義了一些現(xiàn)成的, 又非常好用的應(yīng)用層協(xié)議, 供我們參考使用。 http(超文本傳輸協(xié)議) 就是其中之一,這個協(xié)議就是用戶從服務(wù)器拿視頻、圖片等文件資源的一種協(xié)議。(這些資源存放在服務(wù)器的磁盤上)
2、URL的組成
????????平時我們俗稱的 "網(wǎng)址" 其實就是說的 URL。
????????ip會標(biāo)識一臺網(wǎng)絡(luò)主機,看到"/"就知道這臺網(wǎng)絡(luò)主機用的是Linux系統(tǒng)。使用url就可以通過瀏覽器請求這臺網(wǎng)絡(luò)主機的服務(wù)器,從指定的文件路徑下找到用戶請求的文件返回給用戶。
3、urlencode和urldecode
????????像 / + : ?等字符, 已經(jīng)被url特殊處理了。比如, 某個參數(shù)中需要帶有這些特殊字符, 就必須先對特殊字符進行轉(zhuǎn)義.
????????轉(zhuǎn)義的規(guī)則如下:取出字符的ASCII碼,轉(zhuǎn)成16進制,然后前面加上百分號即可。編碼成%XY格式。服務(wù)器收到url請求,將會對%XY進行解碼,該過程稱為decode,如果哪天需要解碼了,網(wǎng)上搜一下就行,這不是很重要的東西。
????????"+" 被轉(zhuǎn)義成了 "%2B"。urldecode就是urlencode的逆過程。
二、http的請求方法、狀態(tài)碼及狀態(tài)碼描述、常見的響應(yīng)報頭
1、http請求方法
請求方法 |
說明 |
支持的http協(xié)議版本 |
GET |
獲取資源 |
1.0/1.1 |
POST |
傳輸實體主體 |
1.0/1.1 |
其他方法不常用,略。 |
????????GET和POST方法提交參數(shù)的區(qū)別
????????客戶端進行數(shù)據(jù)提交時,是通過前端的from表單提交的,瀏覽器會將from表單中的內(nèi)容轉(zhuǎn)換為GET/POST方法。
1、GET方法通過URL傳遞參數(shù)。例如http://ip:port/XXX/YY?key1=value1&key2=value2。像百度的搜索就是用的GET方法。GET方法通過url傳遞參數(shù),參數(shù)注定不能太大,例如上傳視頻等巨長的二進制文件就不適合用GET了。
2、POST提交參數(shù)通過http請求正文提交參數(shù)。請求正文可以很大,可以提交視頻等巨長的文件。
3、POST方法提交參數(shù),用戶是看不到的,私密性更高,而GET方法不私密。私密性不等于安全性,POST方法和GET方法其實都不安全?。╤ttp請求都是可以被抓到的,想要安全必須加密,使用https協(xié)議)
????????注意:如果用的是GET方法,需要對url進行額外的處理,例如/test.py?key1=value1&key2=value2,需要拆解出其中的路徑(_path),即"test.py"。問號右側(cè)則是參數(shù)(_parm)。
if(req._path=="test.py")
{
//建立進程間通信,pipe
//fork創(chuàng)建子進程,execl("/bin/python",test.py)進行進程程序替換
//父進程,將req._parm通過管道寫給某些后端語言,例如py、java、php等
//....
return true;
}
2、http狀態(tài)碼及狀態(tài)碼描述?
HTTP狀態(tài)碼是由服務(wù)器返回給客戶端的三位數(shù)字代碼,用于表示客戶端請求的處理狀態(tài)。以下是常見的HTTP狀態(tài)碼及其描述:
1xx(信息性狀態(tài)碼):表示請求已被接收,繼續(xù)處理。
2xx(成功狀態(tài)碼):表示請求已成功被服務(wù)器接收、理解、并接受。
- 200 OK:請求成功。
- 201 Created:請求已經(jīng)被實現(xiàn),資源已經(jīng)被創(chuàng)建。
- 204 No Content:請求成功,但響應(yīng)報文不含實體的主體部分。
3xx(重定向狀態(tài)碼):客戶端發(fā)送請求,服務(wù)器返回3XX狀態(tài)碼和一個新的URL,客戶端拿著這個新的URL再次請求服務(wù)器,這就是重定向。
- 301 Moved Permanently:永久性重定向。
- 302 Found:臨時性重定向。
- 304 Not Modified:客戶端已經(jīng)執(zhí)行了GET,但文件未變化。
- 307 Temporary Redirect:臨時性重定向。
4xx(客戶端錯誤狀態(tài)碼):表示客戶端請求出錯,服務(wù)器無法處理請求。
- 400 Bad Request:請求報文存在語法錯誤。
- 401 Unauthorized:未經(jīng)授權(quán),需要身份驗證。
- 403 Forbidden:服務(wù)器拒絕請求。
- 404 Not Found:服務(wù)器無法找到請求的資源。(屬于客戶端錯誤,客戶端請求資源在服務(wù)器不存在)
5xx(服務(wù)器錯誤狀態(tài)碼):表示服務(wù)器處理請求出錯。
- 500 Internal Server Error:服務(wù)器內(nèi)部錯誤。
- 502 Bad Gateway:網(wǎng)關(guān)錯誤。
- 503 Service Unavailable:服務(wù)器暫時無法處理請求。
- 504 Gateway Timeout:網(wǎng)關(guān)超時。
以307狀態(tài)碼為例,臨時重定向至CSDN首頁:
std::string respLine="HTTP/1.1 307 Temporary Redirect\r\n";//重定向,配合"Location: "使用
//響應(yīng)報頭
std::string respHeader=suffdeixDesc(req._suffix);//將后綴轉(zhuǎn)換為對應(yīng)的響應(yīng)報頭
if(req._size>0)
{
respHeader+="Content-Length: ";
respHeader+=std::to_string(req._size);
respHeader+="\r\n";
}
respHeader+="Location: https://www.csdn.net/\r\n";
3、http常見的響應(yīng)報頭
HTTP協(xié)議常見的響應(yīng)報頭包括:
- Content-Type:指定響應(yīng)體的MIME類型,例如text/html表示HTML文本,image/jpeg表示JPEG圖片等。
- Content-Length:指定響應(yīng)體的長度,單位為字節(jié)。
- Cache-Control:指定緩存控制策略,例如no-cache表示不緩存,max-age=3600表示緩存1小時等。
- Expires:指定響應(yīng)過期時間,通常與Cache-Control一起使用。
- Last-Modified:指定資源的最后修改時間,用于協(xié)商緩存。
- ETag:指定資源的唯一標(biāo)識符,用于協(xié)商緩存。
- Location:搭配3XX狀態(tài)碼使用,指定重定向的目標(biāo)URL。
- Set-Cookie:指定響應(yīng)中的Cookie信息。
- Server:指定服務(wù)器軟件的名稱和版本號。
- X-Powered-By:指定服務(wù)器使用的編程語言和框架。
三、http協(xié)議客戶端和服務(wù)器的通信過程
????????以個人云服務(wù)器作服務(wù)器,瀏覽器作客戶端,服務(wù)器打印客戶端請求如圖:
????????這個http請求可以看到請求的設(shè)備信息,如果在手機端瀏覽器搜索“微信下載”,瀏覽器將會返回手機版的微信下載網(wǎng)頁,若在電腦瀏覽器搜索,將會返回電腦版的微信下載網(wǎng)頁。
????????以個人云服務(wù)器作服務(wù)器,瀏覽器作客戶端,服務(wù)器的響應(yīng)格式:
????????Content-Type: text/html\r\n用于指示所傳輸?shù)臄?shù)據(jù)是HTML格式的文本。注意響應(yīng)報頭位置不要打成test了,這些都是設(shè)定好的,如果輸錯了,瀏覽器請求服務(wù)器時,會變成下載html文件!同樣的,圖片的響應(yīng)報頭寫錯了,當(dāng)客戶端請求圖片時,同樣會變成下載邏輯。
1、如何保證請求和響應(yīng)被應(yīng)用層完整的讀取了?
1、可以讀取完整的一行
2、while循環(huán)讀取行,將所有的請求行和請求報頭全部讀完,直到遇到空行
3、我們可以保證把請求行和請求報頭讀完,報頭中有Content-Length:XXX(正文長度)
4、通過Content-Length所示的長度,讀取對應(yīng)長度的正文即可。
????????一個用戶看到的網(wǎng)頁結(jié)果,可能由多個資源組合而成,所以要獲取一張完整的網(wǎng)頁效果,瀏覽器會發(fā)起多次http請求。所以需要根據(jù)客戶端的請求信息,在服務(wù)器設(shè)置好不同的狀態(tài)行和響應(yīng)報頭。
2、請求和響應(yīng)如何做到序列化和反序列化
1、http不用關(guān)注json等序列化和反序列化工具,直接發(fā)送即可。服務(wù)器解析客戶端的請求,獲取其中的信息填充至響應(yīng)緩沖區(qū)。服務(wù)器通過響應(yīng)報頭的方式返回請求的參數(shù),在響應(yīng)正文中返回請求的資源。
2、對于正文部分,如果需要的話,可以設(shè)計自定義序列化與反序列化方案。
3、客戶端和服務(wù)器通信的全過程?
void HandlerHttp(int sock)
{
//1、讀取完整的http請求
char buffer[4096];
HttpRequest req;
HttpResponse resp;
size_t n=recv(sock,buffer,sizeof(buffer)-1,0);//讀取套接字中的內(nèi)容
if(n>0)
{
buffer[n]=0;//添加'\0'
req._inBuffer=buffer;//獲得序列化請求
//2、對客戶端請求進行反序列化
//從客戶端請求中解析獲得請求行(請求方法、請求url、http版本)、請求資源的后綴、請求資源的大小
req.Parse();//對請求進行解析
//3、回調(diào)_func方法,由http請求獲得http響應(yīng) _func(req,resp)
//4、對http響應(yīng)resp進行序列化
_func(req,resp);
//funcs[req._path](req,resp);
send(sock,resp._outBuffer.c_str(),resp._outBuffer.size(),0);//5、send發(fā)送
}
}
步驟2反序列化:解析請求行,從url中獲取請求的資源路徑并計算資源的大小等。
void Parse()//從客戶端請求中解析獲得請求行(請求方法、請求url、http版本)、請求資源的后綴、請求資源的大小
{
//1、從請求結(jié)構(gòu)體中的_inbuffer中拿到請求行(第一行),分隔符\r\n
std::string line=Util::getOneLine(_inBuffer,sep);
if(line.empty()){return;}
//2、從請求行中獲取三個字段:請求方法、請求url、請求版本
//std::cout<<"line:"<<line<<std::endl;
std::stringstream ss(line);
ss>>_method>>_url>>_httpVersion;//以空格為分割讀取其中的字段
//2.1如果是GET方法,需要對_url進行額外處理
///search?name=jiang&pwd=123通過?對GET方法進行左右分離(POST本來就是分離的沒有問號)
//左邊是PATH,右邊是_parm
//3、添加web默認(rèn)路徑
_path=defaultRoot;//客戶端所有請求路徑前都會被加上./wwwroot前導(dǎo)目錄字符串
_path+=_url;//如果客戶端請求a/b/c.html,則會請求./wwwroot/a/b/c.html
if(_path[_path.size()-1]=='/')//如果請求的是web根目錄(./wwwroot/),就讓它訪問設(shè)定好的默認(rèn)首頁的路徑(./wwwroot/index.html)
{
_path+=homePage;
}
//4、獲取path對應(yīng)的資源后綴
//./wwwroot/index.html
//./wwwroot/test/a.html
//./wwwroot/test/b.html
//./wwwroot/image/dog.jpg
auto pos=_path.rfind(".");
if(pos==std::string::npos){_suffix=".html";}//實在找不到,先給個html
else{_suffix=_path.substr(pos);}
//5、得到響應(yīng)正文的大小(客戶端請求資源的大小)
struct stat st;
int n=stat(_path.c_str(),&st);
if(0==n)
{
_size=st.st_size;
}
else{_size=-1;}
}
步驟3、4,由客戶端請求轉(zhuǎn)換為客戶端響應(yīng)(設(shè)置一下不同響應(yīng)方法的狀態(tài)行、響應(yīng)報頭、響應(yīng)正文等信息,這里的響應(yīng)正文是html和圖片)
bool Get(const HttpRequest& req,HttpResponse& resp)
{
// if(req._path=="test.py")
// {
// //建立進程間通信,pipe
// //fork創(chuàng)建子進程,execl("/bin/python",test.py)進行進程程序替換
// //父進程,將req._parm通過管道寫給某些后端語言,例如py、java、php等
// //....
// return true;
// }
// if(req._path=="/search")
// {
// //如果PATH是"/search",可以在這里寫具體的C++方法,提供相應(yīng)的服務(wù)
// //....
// return true;
// }
//打印客戶端的請求的一些信息
std::cout<<"-----------httpStart------------"<<std::endl;
std::cout<<req._inBuffer<<std::endl;
std::cout<<"method:"<<req._method<<std::endl;
std::cout<<"url:"<<req._url<<std::endl;
std::cout<<"httpVersion:"<<req._httpVersion<<std::endl;
std::cout<<"path:"<<req._path<<std::endl;
std::cout<<"suffix:"<<req._suffix<<std::endl;
std::cout<<"size:"<<req._size<<"字節(jié)"<<std::endl;
std::cout<<"-----------httpEnd--------------"<<std::endl;
//服務(wù)器的狀態(tài)行、響應(yīng)報頭、空行、響應(yīng)正文等信息
//狀態(tài)行
std::string respLine="HTTP/1.1 200 OK\r\n";
//std::string respLine="HTTP/1.1 307 Temporary Redirect\r\n";//重定向,配合"Location: "使用
//響應(yīng)報頭
std::string respHeader=suffdeixDesc(req._suffix);//將后綴轉(zhuǎn)換為對應(yīng)的響應(yīng)報頭
if(req._size>0)
{
respHeader+="Content-Length: ";
respHeader+=std::to_string(req._size+1);//為了和后面的body.size()大小匹配
respHeader+="\r\n";
}
//respHeader+="Location: https://www.csdn.net/\r\n";
//寫入Cookie
respHeader+="Set-Cookie: name=12345abcde;Max-Age=120\r\n";//設(shè)置Cookie響應(yīng)報頭
//往后,每次http請求都會自動攜帶曾經(jīng)設(shè)置的所有Cookie,幫助服務(wù)器的鑒權(quán)行為
//空行
std::string respBlack="\r\n";
std::string body;
body.resize(req._size+1);
if(!Util::readFile(req._path,(char*)body.c_str(),req._size))//將_path路徑下的文件內(nèi)容讀到buffer里
{
Util::readFile(html_404,(char*)body.c_str(),req._size);//訪問的資源不存在,body的路徑就是404html的路徑
respLine="HTTP/1.1 404 Not Found\r\n";//同時,狀態(tài)行修改為404
}
std::cout<<"-----------httpStart------------"<<std::endl;
std::cout<<(respLine+respHeader+respBlack)<<std::endl;
std::cout<<"-----------httpEnd--------------"<<std::endl;
resp._outBuffer=respLine+respHeader+respBlack+body;
return true;
}
4、獲取響應(yīng)正文的長度
STAT(2)
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
struct stat {
dev_t st_dev; // 包含文件的設(shè)備ID
ino_t st_ino; // inode號
mode_t st_mode; // 文件保護模式
nlink_t st_nlink; // 硬鏈接數(shù)
uid_t st_uid; // 文件所有者的用戶ID
gid_t st_gid; // 文件所有者的組ID
dev_t st_rdev; // 設(shè)備ID(如果是特殊文件)
off_t st_size; // 總大小,以字節(jié)為單位
blksize_t st_blksize; // 文件系統(tǒng)I/O的塊大小
blkcnt_t st_blocks; // 分配的512B塊數(shù)
time_t st_atime; // 上次訪問時間
time_t st_mtime; // 上次修改時間
time_t st_ctime; // 上次狀態(tài)更改時間
};
用途:函數(shù)stat用于獲取文件的狀態(tài)信息,包括文件類型、文件大小、文件權(quán)限等。函數(shù)stat只能獲取普通文件、目錄、符號鏈接等文件的狀態(tài)信息,無法獲取設(shè)備文件等特殊文件的狀態(tài)信息。
參數(shù):
- path:文件路徑
- buf:存儲文件狀態(tài)信息的結(jié)構(gòu)體指針
返回值:函數(shù)返回值為0表示成功,-1表示失敗。
得到_path路徑下的文件大小,單位字節(jié):
struct stat st;
int n=stat(_path.c_str(),&st);
if(0==n)
{
_size=st.st_size;
}
else{_size=-1;}
四、http長連接
????????http請求是基于tcp協(xié)議的,而tcp是需要進行連接的。對于一個網(wǎng)頁,可能包含多種元素,則需要發(fā)起多次連接。為了減少連接次數(shù),需要客戶端和服務(wù)器均支持長鏈接,建立一條連接,傳輸一份大的資源通過一條連接完成。
Connection: keep-alive
Connection: close
????????如果報頭的"Connection: "顯示是"keep-alive",則代表支持長連接。
五、http會話保持(客戶端Cookie,服務(wù)器session)
????????例如我們打開嗶哩嗶哩的首頁進行登錄操作,哪怕用戶馬上把瀏覽器關(guān)了,短期內(nèi)再次訪問嗶哩嗶哩是不需要用戶重復(fù)登錄操作的。同樣的,當(dāng)我們在嗶哩嗶哩進行頁面跳轉(zhuǎn)時,http協(xié)議并不會記錄用戶信息,但是曾經(jīng)的用戶登錄信息在頁面跳轉(zhuǎn)時并不會丟失。瀏覽器仍會記住上一次登錄的信息。這就是會話保持。
????????其實http請求是無狀態(tài)的,每次請求并不會記錄它曾經(jīng)請求了什么。所以會話保持不是http協(xié)議天然具備的特點,而是瀏覽器為了滿足用戶的使用需求,做了相應(yīng)的工作。
????????用戶在第一次輸入賬號和密碼時,瀏覽器會進行保存(Cookie),近期再次訪問同一個網(wǎng)站,瀏覽器會自動將用戶信息推送給服務(wù)器。像嗶哩嗶哩中某些需要大會員才能觀看的視頻,服務(wù)器都會先獲取用戶信息進行身份判斷,用的就是瀏覽器緩存的信息。這樣只要用戶首次輸入密碼,一段時間內(nèi)將不用再做登錄操作了。
????????但是本地的Cookie如果被不法分子拿到,那不是危險了,所以信息的保存是在服務(wù)器上完成的,服務(wù)器會對每個用戶創(chuàng)建一份獨有的session id,并將其返回給瀏覽器,瀏覽器存到Cookie的其實是session id。但這樣只能保證原始的賬號密碼不會被泄漏,黑客盜取了用戶的session id后仍可以非法登錄,只能靠服務(wù)端的安全策略保障安全,例如賬號被異地登錄了,服務(wù)端察覺后只要讓session id失效即可,這樣異地登錄將會使用戶重新驗證賬號密碼或手機或人臉信息(盡可能確保是本人),一定程度上保障了信息的安全。
服務(wù)器向客戶端返回Cookie:
//寫入Cookie
respHeader+="Set-Cookie: name=12345abcde; Max-Age=120\r\n";//設(shè)置Cookie響應(yīng)報頭,有效期2分鐘
//往后,每次http請求都會自動攜帶曾經(jīng)設(shè)置的所有Cookie,幫助服務(wù)器的鑒權(quán)行為————http會話保持
六、http相關(guān)工具
1、postman——能夠模擬客戶端瀏覽器的行為。
2、fiddler——一個本地抓包工具,作為http調(diào)試使用。(能夠明文抓到本地的POST方法請求正文?。?/p>
所以http協(xié)議并不安全,想要安全還得看https協(xié)議......文章來源:http://www.zghlxwxcb.cn/news/detail-463111.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-463111.html
到了這里,關(guān)于【網(wǎng)絡(luò)編程】一文詳解http協(xié)議(超文本傳輸協(xié)議)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!