在國(guó)內(nèi)做跨境電商怎么上外國(guó)網(wǎng)站杭州網(wǎng)站優(yōu)化服務(wù)
文章目錄
- 一、基本概念
- 1.HTTP
- 2.域名
- 3.默認(rèn)端口號(hào)
- 4.URL
- 二、請(qǐng)求與響應(yīng)
- 1.抓包工具
- 2.基本框架
- 3.簡(jiǎn)易實(shí)現(xiàn)
- 3.1 HttpServer
- 3.2 HttpRequest
- 3.2.1 version1
- 3.2.2 version2
- 3.2.3 version3
- 總結(jié)
- 尾序
一、基本概念
- 常見(jiàn)的應(yīng)用層協(xié)議:
- HTTPS (
H
yperT
extT
ransferP
rotocolS
ecure),安全
的超文本傳輸數(shù)據(jù)。- FTP(
F
ileT
ransferP
rotocol) ,網(wǎng)絡(luò)之間的文件
傳輸。- SMTP(
S
impleM
ailT
ransferP
rotocol),郵件
傳輸。- DNS(
D
omainN
ameS
ystem),域名
解析。- SSH(
S
ecureSH
ell),加密的遠(yuǎn)程登錄
會(huì)話(huà)。
- 一般來(lái)講,大多數(shù)情況用現(xiàn)成的應(yīng)用層協(xié)議即可,但是如果做游戲引擎,或者做一些比較私密,對(duì)安全性要求很高的項(xiàng)目時(shí),可能需要內(nèi)部指定自定義協(xié)議。
1.HTTP
- HTTP(
H
yperT
extT
ransferP
rotocol)是一種用于傳輸超文本數(shù)據(jù)的應(yīng)用層協(xié)議
。 - 應(yīng)用于Web服務(wù)器與Web瀏覽器之間進(jìn)行通信。
- 明文傳輸(可能會(huì)暴露個(gè)人隱私數(shù)據(jù)),因此不安全,但是簡(jiǎn)單易用,被廣泛支持。
- 對(duì)于HTTP的不安全,之后發(fā)展出了HTTPS,即" 安全的HTTP "。
瀏覽器簡(jiǎn)介:
- 瀏覽器簡(jiǎn)單來(lái)看就是處理數(shù)據(jù)的一種工具,瀏覽器可以解析一些常用的應(yīng)用層協(xié)議的數(shù)據(jù),通過(guò)相應(yīng)的連接方式向服務(wù)端發(fā)送請(qǐng)求,接收響應(yīng)并將文件給我們以相應(yīng)的格式呈現(xiàn)出來(lái),具體如何呈現(xiàn)出一個(gè)完美的網(wǎng)頁(yè),則是前端開(kāi)發(fā)人員的工作了,接下來(lái)的內(nèi)容我們會(huì)制作一個(gè)簡(jiǎn)單的網(wǎng)頁(yè) ~
- 市面上的瀏覽器多種多樣,因?yàn)檎莆樟藶g覽器,也就掌握了進(jìn)入網(wǎng)絡(luò)的通道,因此各大公司在早期為了發(fā)展,爭(zhēng)相競(jìng)爭(zhēng)推動(dòng)了瀏覽器技術(shù)的發(fā)展,發(fā)展出了成熟的瀏覽器,目前瀏覽器呈現(xiàn)的一般都是跟搜索引擎相結(jié)合的模式,通過(guò)搜索網(wǎng)址和關(guān)鍵詞,從而使用戶(hù)進(jìn)入目標(biāo)網(wǎng)站。
- 現(xiàn)在由于ChatGpt的出現(xiàn)讓信息可以通過(guò)對(duì)話(huà)的形式體現(xiàn),相比搜索引擎的關(guān)鍵詞搜索更加的便利,讓我們獲取知識(shí)的成本降低了不少,博主也推薦使用ChatGpt之類(lèi)的工具來(lái)提高學(xué)習(xí)效率。
2.域名
?通過(guò) www.baidu.com,我們可以很明顯的辨認(rèn)出這是百度的網(wǎng)址,其實(shí)這就是百度的域名,那我們?cè)賮?lái)看39.156.66.14,這里你可能會(huì)感覺(jué)有點(diǎn)懵逼,其實(shí)這也是百度的網(wǎng)址,不信博主復(fù)制粘貼到瀏覽器去訪(fǎng)問(wèn)一下,下面截圖為證:
這一串?dāng)?shù)字是怎么得到的呢?
-
按下
win + r
,輸入cmd
,按下回車(chē)?!?windows系統(tǒng)下 -
在命令窗口輸入
ping www.baidu.com
?這其實(shí)是百度的IP地址,通過(guò)它,我們就可以定位唯 一 一 臺(tái)主機(jī)
,進(jìn)而訪(fǎng)問(wèn)百度的服務(wù)器,獲取相應(yīng)的首頁(yè)資源。此時(shí)我們?cè)倩氐接懻摰脑?huà)題,域名相比ip地址,用戶(hù)記憶的成本更低,這就是域名的好處
,但從專(zhuān)業(yè)的角度來(lái)看,域名背后其實(shí)綁定了ip地址,而且可能還不止一個(gè)
,如果你ping的ip地址跟我的不一樣,就證明了這一點(diǎn)。
3.默認(rèn)端口號(hào)
常見(jiàn)的默認(rèn)端口號(hào)有:
- HTTP: 80
- HTTPS: 443
- FTP: 21
- SSH: 22
- Telnet: 23
- SMTP: 25
- POP3: 110
- IMAP: 143
- DNS: 53
- 端口號(hào)所在文件:
/etc/services
這些端口號(hào)一般是不允許被修改的,就像110在我們的腦中已經(jīng)跟報(bào)警電話(huà)已經(jīng)聯(lián)系了起來(lái),80就是http協(xié)議的默認(rèn)端口,而且這些端口號(hào)在訪(fǎng)問(wèn)時(shí)一般瀏覽器是忽略的,如果改了還得在后面跟上: + 修改的端口號(hào)
,因?yàn)閱螒{ip地址只能鎖定一臺(tái)主機(jī),還得指定端口號(hào)與相應(yīng)的進(jìn)程才能進(jìn)行聯(lián)系
,因?yàn)?code>網(wǎng)絡(luò)的本質(zhì)就是進(jìn)程間通信。
4.URL
- 概念
- URL(
U
niformR
esourceL
ocator)是統(tǒng)一資源定位符的縮寫(xiě),用于指定互聯(lián)網(wǎng)上資源的位置和訪(fǎng)問(wèn)方式。簡(jiǎn)單的理解其實(shí)就是網(wǎng)址。
- URL(
- 組成
圖解:
- 例1:ssh登錄
- 例二:http協(xié)議
下面我們于查詢(xún)字符串和片段標(biāo)識(shí)符舉兩個(gè)例子:
- 字符串查詢(xún):
搜索引擎上輸入
C++##
等帶特殊字符的關(guān)鍵詞。查看URL的查詢(xún)參數(shù):
- 如下圖:
- 可見(jiàn)這些特殊字符是被編碼了的,不過(guò)網(wǎng)上有現(xiàn)成的urlencode解碼工具,進(jìn)去將此字符串復(fù)制進(jìn)行轉(zhuǎn)換,可以查看到我們?cè)瓉?lái)的查詢(xún)的關(guān)鍵詞。
- 如下圖:
- 因此我們可以簡(jiǎn)單的理解查詢(xún)不只是簡(jiǎn)單的查詢(xún),還要經(jīng)過(guò)編碼,從而
避免與網(wǎng)址的符號(hào)進(jìn)行沖突
。
- 片段標(biāo)識(shí)符:
- 當(dāng)我們想要在網(wǎng)址中定位某一個(gè)網(wǎng)頁(yè)的位置時(shí),需要通過(guò)片段標(biāo)識(shí)符。
- 博主上一篇文章的網(wǎng)址 :
https://blog.csdn.net/Shun_Hua/article/details/136523510?spm=1001.2014.3001.5501
。后面跟上和不跟上#_729
,對(duì)比效果即可明白片段標(biāo)識(shí)符的作用。
如何找到片段標(biāo)識(shí)符呢?
- 在網(wǎng)頁(yè)中右鍵,選擇選項(xiàng)中的檢查。查看網(wǎng)頁(yè)源代碼。
- 按下
ctrl + f
在搜索框 搜索id
這個(gè)標(biāo)簽。
- 例:
- 鼠標(biāo)移動(dòng)至此,可在網(wǎng)頁(yè)上看到對(duì)應(yīng)的效果,即標(biāo)記位置信息。
二、請(qǐng)求與響應(yīng)
1.抓包工具
- fiddler,需要輸入認(rèn)證信息之后才可進(jìn)行下載。
- postman, 外網(wǎng)的訪(fǎng)問(wèn)會(huì)有些慢,需要使用魔法,或許訪(fǎng)問(wèn)不上。
- apifox,國(guó)內(nèi)的比較好用。
2.基本框架
我們先使用telnet工具進(jìn)行簡(jiǎn)單的HTTP請(qǐng)求,查看請(qǐng)求與響應(yīng)的格式:
因此可以大致列出請(qǐng)求與響應(yīng)的基本框架:
穿插知識(shí):
- 短連接:瀏覽器通常建立連接只能發(fā)一個(gè)請(qǐng)求,然后收一個(gè)響應(yīng),之后斷開(kāi)連接。若想再發(fā)送一個(gè)請(qǐng)求,只能再次申請(qǐng)連接,這適用于
無(wú)需多數(shù)據(jù)傳輸,無(wú)需保持連接,Http/1.0采用的是短連接
。- 長(zhǎng)連接:瀏覽器通常建立連接之后會(huì)保持一段時(shí)間,直接可以進(jìn)行多次數(shù)據(jù)的傳輸,可以一次發(fā)送多個(gè)請(qǐng)求,接收多個(gè)響應(yīng),在無(wú)數(shù)據(jù)傳輸之后會(huì)斷開(kāi)連接。相比短連接減少因頻繁建立和關(guān)閉連接而產(chǎn)生的額外開(kāi)銷(xiāo),提高通信效率,尤其
適用于需要頻繁交換數(shù)據(jù)的場(chǎng)景,Http/1.1版本支持長(zhǎng)連接
。- 說(shuō)明:在請(qǐng)求報(bào)頭中如果有
Connection: keep-alive
,則意味申請(qǐng)長(zhǎng)連接,申請(qǐng)成功時(shí),會(huì)在響應(yīng)報(bào)頭處添加:Connection: keep-alive
。
3.簡(jiǎn)易實(shí)現(xiàn)
?在簡(jiǎn)易的了解Http的請(qǐng)求和響應(yīng)的框架之后,我們可以通過(guò)代碼,編寫(xiě)一個(gè)簡(jiǎn)單的Http服務(wù)器,并且制作一個(gè)簡(jiǎn)單的網(wǎng)頁(yè),來(lái)逐步理解Http的請(qǐng)求和響應(yīng)。
3.1 HttpServer
在之前的文章,我們實(shí)現(xiàn)過(guò)守護(hù)進(jìn)程,日志,封裝基于TCP的socket等小組件,下面避免代碼冗余就不再給出,下面的HttpServer其實(shí)就是一個(gè)基于TCP協(xié)議的服務(wù)端,寫(xiě)多了不管什么類(lèi)型的服務(wù)端就是一種套路:
- 隨機(jī)綁定端口與IP地址進(jìn)行初始化。
- 對(duì)服務(wù)端進(jìn)行初始化,即創(chuàng)建,綁定,監(jiān)聽(tīng)套接字。
- 啟動(dòng)服務(wù)端,接收請(qǐng)求,建立鏈接,提供服務(wù)。
- 提供服務(wù),其實(shí)就是將接收信息并對(duì)信息進(jìn)行處理并返回。
關(guān)鍵就在于這個(gè)處理邏輯,按照什么方式處理,就決定了服務(wù)端是什么類(lèi)型的。
- 實(shí)現(xiàn)代碼:
#pragma once
#include<iostream>
#include<fstream>
#include<functional>
//容器
#include<vector>
#include<unordered_map>
//網(wǎng)絡(luò)接口
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>//小組件
#include "../Tools/Log.hpp"
#include "../Tools/Socket.hpp"
using cal_t = function<string(string&)>;
string default_ip = "0.0.0.0";
uint16_t default_port = 8080;
class HttpServer;
struct PthreadData
{PthreadData(int sockfd,HttpServer* hsp):fd(sockfd),hp(hsp){}int fd;HttpServer* hp;
};
class HttpServer
{
public:HttpServer(uint16_t port = default_port,\cal_t signal = nullptr,string ip = default_ip):_sockfd(port,ip){}void Init(){_sockfd.Socket();//使端口號(hào)可以重復(fù)被使用,之后的TCP內(nèi)容中會(huì)詳談。int opt = 1;setsockopt(_sockfd.GetSocket(),SOL_SOCKET,\SO_REUSEADDR|SO_REUSEPORT\,&opt,sizeof(opt));_sockfd.Bind();_sockfd.Listen();}static void *Routine(void* args){pthread_detach(pthread_self());auto thp = static_cast<PthreadData*>(args);HttpServer* hp = thp->hp;int fd = thp->fd;hp->Server(fd);return nullptr;}void Run(){for(;;){sockaddr_in client;socklen_t len;int fd = _sockfd.Accept(&client,&len);pthread_t tid;pthread_create(&tid,nullptr,Routine\,new PthreadData(fd,this));}}void Server(int fd){string mes;for(;;){mes += _sockfd.Read(fd);if(mes == "") break;//處理信息string echo_mes = cal(mes);int num = _sockfd.Write(fd,echo_mes);if(num == 0) break;}_sockfd.Close(fd);}
private:Sock _sockfd;cal_t cal;
};
3.2 HttpRequest
如下是我們實(shí)現(xiàn)處理請(qǐng)求類(lèi)的宏觀框架,讀者有個(gè)大致的認(rèn)識(shí)即可,博主下面會(huì)分別行進(jìn)行實(shí)現(xiàn),逐一進(jìn)行講解。
- 實(shí)現(xiàn)代碼:
struct HttpRequest
{ //構(gòu)造函數(shù)。HttpRequest();//從請(qǐng)求中獲取一個(gè)完整的報(bào)文string InCode(string& str);//從報(bào)文中將請(qǐng)求的信息進(jìn)行打散。bool Deserialize(string& str);//對(duì)請(qǐng)求報(bào)頭解析并獲取對(duì)應(yīng)的內(nèi)容。void Prase()//從指定目錄中讀取相關(guān)消息并進(jìn)行返回。string ReadFromFile(const string& path)//獲取返回網(wǎng)絡(luò)的文件的類(lèi)型。string GetContentType()//解析URL獲取對(duì)應(yīng)的網(wǎng)絡(luò)資源。string GetSourse();//處理服務(wù)器收到的請(qǐng)求。string HanderHttpMes(string &mes);
public://正文之前的部分vector<string> infors;//提供文件在網(wǎng)絡(luò)中的類(lèi)型。unordered_map<string,string> content_type;//請(qǐng)求方法,大多數(shù)為POST和GET方法。string Method;//統(tǒng)一資源定位符。string Url;//URL里面可能有讀取文件信息,請(qǐng)求的都是網(wǎng)頁(yè)文件。string suffix = ".html";//HTTP的版本,一般為1.1或者1.0的。string Version; //請(qǐng)求正文,一般來(lái)說(shuō)響應(yīng)是沒(méi)有的。string content;//獲取資源在服務(wù)器的路徑,即根目錄。const string root = "./wwwroot";
};
- 主程序:
#include<iostream>
#include<memory>#include "httpserver.hpp"void Usage(char* pragma_name)
{cout << endl << "Usage: " << pragma_name \<< " + port[8000-8888]" << endl << endl;
}
int main(int argc,char* argv[])
{if(argc != 2){Usage(argv[0]);return 1;}uint16_t port = stoi(argv[1]);HttpRequest req;std::unique_ptr<HttpServer> htp(new HttpServer(port,\bind(&HttpRequest::HanderHttpMes,&req,placeholders::_1)));//bind函數(shù):指定類(lèi)域,固定this指針,以及參數(shù),從而封裝//出了一個(gè)返回值為string類(lèi)型,參數(shù)為string&的函數(shù)。htp->Init();htp->Run();return 0;
}
- 對(duì)請(qǐng)求的處理和程序的運(yùn)行有了宏觀的認(rèn)識(shí)之后,下面我們先來(lái)編寫(xiě)一段代碼,在網(wǎng)頁(yè)中打印出簡(jiǎn)單的消息。
- HanderHttpMes的實(shí)現(xiàn):
3.2.1 version1
version1:打印出簡(jiǎn)單的信息。
string HanderHttpMes(string &mes){//避免mes過(guò)長(zhǎng),我們將其清空。mes = "";//空行string empty_line = "\r\n"; //狀態(tài)行string state_line = "HTTP/1.1 200 OK\r\n";//正文string text = "hello world\r\n"; //報(bào)文段string package_line = "Content-Length: " +\to_string(text.size()) + empty_line;//響應(yīng)string response = state_line + package_line +\empty_line + text;return response;}
- 運(yùn)行結(jié)果:
- 效果:
看到效果之后,我們便可大致明白,瀏覽器其實(shí)就是接收信息的客戶(hù)端,并按照自定義協(xié)議將信息給上層用戶(hù)進(jìn)行呈現(xiàn)。
運(yùn)用知識(shí):
Content-Length:【空格】【正文段長(zhǎng)度】【\r\n】
—— 狀態(tài)行信息,用于瀏覽器的獲取正文段數(shù)據(jù),并按照指定的方式呈現(xiàn)出來(lái),這里我們只是打印出了文字。
- 缺陷:不管瀏覽器給我們發(fā)送什么請(qǐng)求,我們都只會(huì)返回hello world進(jìn)行響應(yīng)。
3.2.2 version2
version2: 完成請(qǐng)求的解析,提取出url,返回對(duì)應(yīng)的網(wǎng)頁(yè)資源。
- 請(qǐng)求解析。
- 思路:
1. 首先我們從緩存區(qū)中提取的不知道是否是一個(gè)完整的報(bào)文。
2. 因此我們應(yīng)找到完整報(bào)文的解析符 ——\r\n\r\n
。
3. 一般情況下,瀏覽器是不會(huì)發(fā)送正文段的,因此我們按照沒(méi)有發(fā)送正文段的報(bào)文進(jìn)行解析處理。- 拓展:我們可以看已經(jīng)截取的請(qǐng)求報(bào)頭中查看是否有Content-Length字段,如果有則有正文,解析其后的數(shù)據(jù)長(zhǎng)度,截取正文段即可。
- InCode
string InConde(string& str){string splite_str = "\r\n\r\n";size_t pos = str.find(splite_str,0);//如果沒(méi)有找到說(shuō)明不是一個(gè)完整的報(bào)文。if(pos == string::npos){return "";}int len = pos + splite_str.size();string package = str.substr(0,len);//將報(bào)文進(jìn)行丟棄,便于截取下一次請(qǐng)求的報(bào)文。str.erase(0,len);return package; }
- 打散請(qǐng)求
- 思路:
因?yàn)槎际且?code>\r\n以一行的形式進(jìn)行呈現(xiàn)的,因此我們只需以\r\n
截取出每一行即可,然后添加到類(lèi)型為vector<string> 的infors
即可。
- Deserialize
bool Deserialize(string& str){//先看是否有完整的報(bào)文string datagram = InConde(str);int cur = 0;while(true){size_t pos = datagram.find(line_break,cur);//從cur位置開(kāi)始尋找。//如果沒(méi)有就說(shuō)明解析出錯(cuò)了。if(pos == string::npos) return false;string line = datagram.substr(cur,pos - cur); //截取pos - cur長(zhǎng)度。cur = pos + line_break.size();//跳過(guò)line_breakif(line.empty()) break; //讀取到空行。infors.push_back(line);}return true;}
- 提取狀態(tài)行。
- 思路:
- 這里報(bào)文都存在
infors中
, 請(qǐng)求報(bào)頭都在infors[0]
中,因此我們將其解析出來(lái)即可。- 格式為:
[請(qǐng)求方法][空格][Url][空格][HTTP版本]
,以空格分隔出每一個(gè)元素即可。
除此之外,因?yàn)槲覀円獜膗rl中解析出相應(yīng)的返回資源,下面我們列出第一次訪(fǎng)問(wèn)網(wǎng)址瀏覽器發(fā)送的兩次請(qǐng)求:
- 說(shuō)明: 第一次請(qǐng)求的是主頁(yè)資源,主頁(yè)資源的url也可以為 /index.html,第二次請(qǐng)求的是網(wǎng)頁(yè)標(biāo)簽的logo。
- 舉個(gè)百度標(biāo)簽的logo:
根據(jù)url解析出相應(yīng)的文件信息,我們可以據(jù)此返回相應(yīng)的資源了。
- Prase
void Prase(){//對(duì)一行的資源進(jìn)行處理string state_line = infors[0]; //[請(qǐng)求方法][空格][Url][空格][HTTP版本]auto left = state_line.find(space);auto right = state_line.rfind(space);//請(qǐng)求方法Method = state_line.substr(0,left);//urlUrl = state_line.substr(left + 1,right - left - 1);//請(qǐng)求的HTTP版本。Version = state_line.substr(right + 1);//看URL中是否帶有文件信息,如果有則解析出來(lái),默認(rèn)為 ".html"auto pos = Url.rfind('.');if(pos != string::npos){suffix = Url.substr(pos);//默認(rèn)為.htmlif(content_type[suffix] == "") suffix = ".html";}}
- 構(gòu)造函數(shù):
HttpRequest(){content_type[".jpg"] = "image/jpeg";content_type[".html"] = "text/html";content_type[".ico"] = "image/x-icon";}
- 說(shuō)明:
- 響應(yīng)時(shí),我們返回對(duì)應(yīng)網(wǎng)頁(yè)資源時(shí),得說(shuō)明是什么類(lèi)型的,瀏覽器會(huì)按照響應(yīng)的方式進(jìn)行解析。
- 我們只需再狀態(tài)行添加
[Content-Type:][空格][資源文件的類(lèi)型]
,比如:Content-Type: text/html
。
- 準(zhǔn)備網(wǎng)頁(yè)資源。
我們?cè)诋?dāng)前目錄下創(chuàng)建一個(gè)wwwroot
作為根目錄,存放網(wǎng)頁(yè)資源文件,一般的網(wǎng)頁(yè)以 .html
結(jié)尾。
因此我們成員變量設(shè)置了:
const string root = "./wwwroot"; //獲取資源在服務(wù)器的路徑,即根目錄。
我們這里創(chuàng)建一個(gè)index.html
,寫(xiě)一些網(wǎng)頁(yè)信息:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Shun_Hua</title>
</head>
<body><h1 >歡迎來(lái)到我的主頁(yè)!</h1>
</body>
</html>
- 說(shuō)明:
- 首先博主采用的是vscode編寫(xiě)較為輕量,寫(xiě)起來(lái)也很輕松,按下
! 加上 Tab
可以快速生成一個(gè)網(wǎng)頁(yè)框架。- 這里涉及一些前端的知識(shí),博主在寫(xiě)項(xiàng)目時(shí)候總結(jié)了一下常用的,具體可見(jiàn):詳見(jiàn)目錄前端編寫(xiě)模塊 。
下面是如何找的過(guò)程,首先我們要從url獲取到文件的信息,再跟網(wǎng)頁(yè)的根目錄進(jìn)行拼接,具體實(shí)現(xiàn)如下:
- GetSourse
string GetSourse(){//根據(jù)Url,確定返回的資源string path = root;//主頁(yè)資源。if(Url == "/" || Url == "/home.html")path += "/home.html";else{path += Url;}//從文件中讀取消息。return ReadFromFile(path);}
下一步是從獲取到的具體路徑文件中,讀取文件信息,作為正文段進(jìn)行返回。
- ReadFromFile
string ReadFromFile(const string& path){//從文件中讀取對(duì)應(yīng)的內(nèi)容。std::ifstream fs(path,ios_base::in);if(!fs.is_open()) return "404 Not Found";string content;//直接讀取到文件的結(jié)尾fs.seekg(0,fs.end);//獲取文件的長(zhǎng)度。auto len = fs.tellg();//回退到文件的長(zhǎng)度。fs.seekg(0,fs.beg);//直接將內(nèi)容讀取出來(lái),將內(nèi)容打到進(jìn)去,這是比較暴力但是比較簡(jiǎn)單的做法。content.resize(len);fs.read((char*)content.c_str(),content.size());return content;}
以上的代碼寫(xiě)完之后,我們可以再寫(xiě)一個(gè)更加高級(jí)的處理消息的函數(shù):
- HanderHttpMes
string HanderHttpMes(string &mes){HttpRequest req;//首先對(duì)mes進(jìn)行解析,獲取完整的報(bào)文,解析失敗返回空串。if(!req.Deserialize(mes)) return "";//其次解析出報(bào)頭信息。req.Prase();//從Url中獲取相應(yīng)的網(wǎng)頁(yè)資源。string text = req.GetSourse(); //正文string empty_line = "\r\n"; //空行string state_line = "HTTP/1.1 200 OK\r\n";//狀態(tài)行string package_line = "Content-Length: " \+ to_string(text.size()) + empty_line;string content_type_line = "Content-Type: "\+ content_type[suffix] + empty_line;string response = state_line + package_line + empty_line + text;return response;}
- 效果:
- 返回的響應(yīng):
下面我們來(lái)一點(diǎn)前端的知識(shí),讓頁(yè)面更加豐富多采一點(diǎn):
- 增加網(wǎng)頁(yè)標(biāo)簽logo
- 推薦網(wǎng)站:免費(fèi)Favicon.ico圖標(biāo)在線(xiàn)生成器
- 這里我輸入文字:舜華,進(jìn)行自動(dòng)生成?;蛘咧苯佑矛F(xiàn)成的也可以。
- 點(diǎn)擊圖片下載保存到能找到的文件夾。
- 在Linux會(huì)話(huà)窗口使用:
rz -E
命令,將.ico
文件上傳到Linux的存放網(wǎng)頁(yè)文件的目錄下。
然后我們?cè)偎⑿戮W(wǎng)頁(yè),看一看效果:
- 有總比沒(méi)有強(qiáng),雖然顏色有點(diǎn)重,hhh。
此后,我們可以直接在網(wǎng)頁(yè)文件中編寫(xiě)內(nèi)容,服務(wù)器啟動(dòng)著,瀏覽器刷新即可更新出新的網(wǎng)頁(yè)內(nèi)容。
- 說(shuō)明:以下所有更新文件都在
./wwwroot
路徑下。
更新網(wǎng)頁(yè)內(nèi)容:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Shun_Hua</title>
</head>
<body><h1 >歡迎來(lái)到我的主頁(yè)!</h1><!-- >更新內(nèi)容,添加網(wǎng)頁(yè)鏈接,可以跳轉(zhuǎn)到指定網(wǎng)頁(yè) <--><a href="http://59.110.171.164:8888/"> 回到主頁(yè) </a></br> <!-- >回車(chē)換行的意思<--><a href="http://59.110.171.164:8888/tail.html"> 尾頁(yè) </a>
</body>
</html>
添加尾頁(yè)內(nèi)容:
- tail.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>尾頁(yè)</title>
</head>
<body><h1>歡迎來(lái)到尾頁(yè)!</h1><p>ps:功能開(kāi)發(fā)中……</p><a href="http://59.110.171.164:8888/"> 回到主頁(yè) </a>
</body>
</html>
刷新界面:
在尾頁(yè)添加圖片:
- 圖片 ——1.png
- tail.html
<!-- >說(shuō)明:未補(bǔ)充內(nèi)容同上 <-->
<body><h1>歡迎來(lái)到尾頁(yè)!</h1><p>ps:功能開(kāi)發(fā)中……</p><a href="http://59.110.171.164:8888/"> 回到主頁(yè) </a><br><img src = "./1.jpg" alt="實(shí)在抱歉" width="200px" height="200px"><!-- >加載對(duì)應(yīng)的圖片,設(shè)置圖片加載失敗時(shí)的提示,設(shè)置圖片的寬度和高度 <-->
</body>
效果:
- 綜上所述,我們使用一點(diǎn)點(diǎn)前端知識(shí),將網(wǎng)頁(yè)變的不至于那么單調(diào),簡(jiǎn)單的完成與用戶(hù)進(jìn)行交互。
- 說(shuō)明:以上都是請(qǐng)求成功的情況,那有沒(méi)有請(qǐng)求失敗的的情況呢?下面我們繼續(xù)深入了解
響應(yīng)行和響應(yīng)報(bào)頭
。
3.2.3 version3
- version3: 學(xué)習(xí)響應(yīng)行和響應(yīng)報(bào)頭。
- 重定向
- 狀態(tài)碼:3XX,重定向,需要進(jìn)一步的操作以完成請(qǐng)求。這里使用 302 Found。
- 狀態(tài)行: 既然重定向了,我們還得告訴瀏覽器的重定向的地址是什么,這里我們使用302,狀態(tài)行表示成:
[Location:][空格][網(wǎng)址][\r\n]
。
- HanderHttpMes
string HanderHttpMes(string &mes){HttpRequest req;string state_line = "HTTP/1.1 302 Found\r\n";//狀態(tài)行string location_line = "Location: https://www.baidu.com\r\n";string empty_line = "\r\n"; //空行string response = state_line + location_line + empty_line;return response;}
- 效果:
2. 網(wǎng)頁(yè)資源不存在
- 狀態(tài)碼:4XX,客戶(hù)端錯(cuò)誤,請(qǐng)求包含語(yǔ)法錯(cuò)誤或無(wú)法完成請(qǐng)求。這里使用 404 Not Found。
- 狀態(tài)行: 既然找不到,我們就返回一個(gè)表示找不到的網(wǎng)頁(yè)即可。
- HanderHttpMes
string HanderHttpMes(string &mes){//如果解析出來(lái)的Url不存在,我們可以直接返回錯(cuò)誤界面,//這里我們只是簡(jiǎn)單的演示一下效果。mes.resize(0);HttpRequest req;string text = ReadFromFile(root + "/errno.html") + "\r\n";string state_line = "HTTP/1.1 404 Not Found\r\n";//狀態(tài)行string len_line = "Content-Length: " + to_string(text.size()) + "\r\n"; string empty_line = "\r\n"; //空行string response = state_line + len_line + empty_line + text;return response;}
- errno.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>404 Not Found</title>
<style>
body {
text-align: center;
padding: 150px;
}
h1 {
font-size: 50px;
}
body {
font-size: 20px;
}
a {
color: #008080;
text-decoration: none;
}
a:hover {
color: #005F5F;
text-decoration: underline;
}
</style>
</head>
<body>
<div>
<h1>404</h1>
<p>頁(yè)面未找到<br></p>
<p>
您請(qǐng)求的頁(yè)面可能已經(jīng)被刪除、更名或者您輸入的網(wǎng)址有誤。<br>
請(qǐng)嘗試使用以下鏈接或者自行搜索:<br><br>
<a href="https://www.baidu.com">百度一下></a>
</p>
</div>
</body>
</html>
- 說(shuō)明:網(wǎng)上有現(xiàn)成的,直接拿來(lái)用即可。
- 效果:
- 設(shè)置cookie
概念:cookie是一種文本文件,會(huì)進(jìn)行存儲(chǔ)記錄用戶(hù)的相關(guān)信息,發(fā)送給服務(wù)器進(jìn)行認(rèn)證。
優(yōu)點(diǎn):下一次登錄時(shí),會(huì)直接用已經(jīng)存儲(chǔ)好的cookie文件,無(wú)需再次登錄認(rèn)證。
- 圖解:
如何查看呢?下面我們以CSDN的首頁(yè)進(jìn)行舉例。
說(shuō)明:cookie文件是有保質(zhì)期的,過(guò)期了cookie會(huì)無(wú)效,需要再次認(rèn)證。
- HanderHttpMes
string HanderHttpMes(string &mes){//如果解析出來(lái)的Url不存在,我們可以直接返回錯(cuò)誤界面,//這里我們只是簡(jiǎn)單的演示一下效果。HttpRequest req;if(!req.Deserialize(mes)) return "";req.Prase();string text = req.GetSourse();string state_line = "HTTP/1.1 200 OK\r\n";//狀態(tài)行string len_line = "Content-Length: " + to_string(text.size()) + "\r\n";string cookie_line = "Set-Cookie: user=shun_hua&&password=123456\r\n"; string empty_line = "\r\n"; //空行string response = state_line + len_line + cookie_line + empty_line + text;return response;}
-
效果:
-
網(wǎng)頁(yè)中的cookie文件:
- 這里總結(jié)一下對(duì)響應(yīng)和請(qǐng)求的大致分類(lèi):
- 狀態(tài)碼
狀態(tài)碼 | 狀態(tài)描述 |
---|---|
1XX | 信息,服務(wù)器收到請(qǐng)求,需要請(qǐng)求者繼續(xù)執(zhí)行操作 |
2XX | 成功,操作被成功接收并處理 |
3XX | 重定向,需要進(jìn)一步的操作以完成請(qǐng)求 |
4XX | 客戶(hù)端錯(cuò)誤,請(qǐng)求包含語(yǔ)法錯(cuò)誤或無(wú)法完成請(qǐng)求 |
5XX | 服務(wù)器錯(cuò)誤,服務(wù)器在處理請(qǐng)求的過(guò)程中發(fā)生了錯(cuò)誤 |
- 當(dāng)我們使用具體的狀態(tài)碼時(shí),查表即可,但是我們要對(duì)狀態(tài)碼的分類(lèi)比較清楚,上面我們使用了404,302,200進(jìn)行了演示。
- Header
Header | 描述 |
---|---|
Content-Type: | 數(shù)據(jù)類(lèi)型(text/html等) |
Content-Length: | Body的長(zhǎng)度 |
Host: | 客戶(hù)端告知服務(wù)器, 所請(qǐng)求的資源是在哪個(gè)主機(jī)的哪個(gè)端口上; |
User-Agent: | 聲明用戶(hù)的操作系統(tǒng)和瀏覽器版本信息; |
referer: | 當(dāng)前頁(yè)面是從哪個(gè)頁(yè)面跳轉(zhuǎn)過(guò)來(lái)的; |
location: | 搭配3xx狀態(tài)碼使用, 告訴客戶(hù)端接下來(lái)要去哪里訪(fǎng)問(wèn); |
Cookie: | 用于在客戶(hù)端存儲(chǔ)少量信息. 通常用于實(shí)現(xiàn)會(huì)話(huà)(session)的功能 |
- 常用狀態(tài)碼與響應(yīng)頭
- 請(qǐng)求方法
請(qǐng)求方法 | 描述 |
---|---|
GET | 請(qǐng)求指定的頁(yè)面信息,并返回實(shí)體主體。 |
POST | 向指定資源提交數(shù)據(jù)進(jìn)行處理請(qǐng)求(例如提交表單或者上傳文件)。數(shù)據(jù)被包含在請(qǐng)求體中。POST 請(qǐng)求可能會(huì)導(dǎo)致新的資源的建立和/或已有資源的修改。 |
HEAD | 類(lèi)似于 GET 請(qǐng)求,只不過(guò)返回的響應(yīng)中沒(méi)有具體的內(nèi)容,用于獲取報(bào)頭 |
PUT | 從客戶(hù)端向服務(wù)器傳送的數(shù)據(jù)取代指定的文檔的內(nèi)容。 |
DELETE | 請(qǐng)求服務(wù)器刪除指定的頁(yè)面。 |
CONNECT | HTTP/1.1 協(xié)議中預(yù)留給能夠?qū)⑦B接改為管道方式的代理服務(wù)器。 |
OPTIONS | 允許客戶(hù)端查看服務(wù)器的性能。 |
TRACE | 回顯服務(wù)器收到的請(qǐng)求,主要用于測(cè)試或診斷。 |
PATCH | 是對(duì) PUT 方法的補(bǔ)充,用來(lái)對(duì)已知資源進(jìn)行局部更新 。 |
- 說(shuō)明:大多數(shù)請(qǐng)求都是Get和Post,其它的我們當(dāng)做了解即可。
總結(jié)
- 我們認(rèn)識(shí)了一些現(xiàn)成的應(yīng)用層協(xié)議,比如SMTP,FTP,SSH等。
- 了解了Http的基本概念,比如域名,默認(rèn)端口號(hào),統(tǒng)一資源定位符。
- 介紹了三個(gè)抓包工具,fiddler,postman,apifox。
- 使用telnet工具發(fā)送請(qǐng)求,接收響應(yīng)。并列出了請(qǐng)求和響應(yīng)的框架,據(jù)此學(xué)習(xí)了長(zhǎng)連接和短連接的知識(shí)。
- 編程實(shí)踐,編寫(xiě)一個(gè)網(wǎng)絡(luò)的Server服務(wù)和Request類(lèi)處理請(qǐng)求,通過(guò)此學(xué)習(xí)了常用的請(qǐng)求行的狀態(tài)碼,請(qǐng)求報(bào)頭等,一些網(wǎng)頁(yè)的前端知識(shí),比如標(biāo)題logo,圖片,鏈接,編寫(xiě)了一個(gè)簡(jiǎn)單網(wǎng)頁(yè)。
- 下期預(yù)告:
我們此文提及了cookie一般是含認(rèn)證信和密碼之類(lèi)的信息
,但http是明文傳輸?shù)?/code>,這就導(dǎo)致了數(shù)據(jù)在網(wǎng)絡(luò)中是不安全的,這就涉及到了加密,據(jù)此引出下篇文章要討論的
Https
,敬請(qǐng)期待!。
尾序
我是舜華,期待與你的下一次相遇!