學(xué)院網(wǎng)站建設(shè)進(jìn)度情況說(shuō)明書(shū)seo自動(dòng)排名軟件
文章目錄
- url統(tǒng)一資源定位符
- http協(xié)議介紹
- GET vs POST
- http狀態(tài)碼
- http常見(jiàn)header
- cookie + session
上篇博客定制了一個(gè)協(xié)議,該協(xié)議用來(lái)進(jìn)行簡(jiǎn)單的計(jì)算,其包含了數(shù)據(jù)的序列化和反序列化,編碼和解碼的定制,并且該協(xié)議基于TCP通信,是一種客戶端請(qǐng)求服務(wù)端響應(yīng)的模型。如果你也實(shí)現(xiàn)了一個(gè)自己的協(xié)議,肯定會(huì)有疑問(wèn):自己定制的協(xié)議不夠成熟,而且應(yīng)用場(chǎng)景有限,有沒(méi)有一個(gè)成熟且應(yīng)用場(chǎng)景廣泛的協(xié)議?這還真有,它就是上網(wǎng)必須使用的協(xié)議——http,https
url統(tǒng)一資源定位符
要了解http就要先了解url
協(xié)議名:表示該url采用的協(xié)議
登錄信息:一般在url中被隱去,其體現(xiàn)在http請(qǐng)求的報(bào)頭或者正文當(dāng)中
服務(wù)器地址:也稱域名,域名最終會(huì)被解析為IP地址
服務(wù)器端口號(hào):網(wǎng)絡(luò)通信的本質(zhì)是進(jìn)程間通信,所以需要告知IP+端口號(hào),使通信能夠進(jìn)行。但是由于服務(wù)器的端口號(hào)通常是固定的,不寫(xiě)端口號(hào)時(shí),端口號(hào)也能通過(guò)其他特殊方法得知,通信照樣能進(jìn)行
文件路徑:用具體的路徑來(lái)表示想要訪問(wèn)服務(wù)器的哪些資源
查詢字符串:通常用來(lái)過(guò)濾網(wǎng)頁(yè)中的信息,得到想要的信息
片段標(biāo)識(shí)符:也稱錨點(diǎn),用來(lái)指定網(wǎng)頁(yè)的??课恢?#xff0c;或者音視頻的播放位置
可以看到,url中不同字段需要用特殊符號(hào)進(jìn)行分隔,這就意味著每一字段中不能出現(xiàn)這些特殊符號(hào),或者說(shuō)如果出現(xiàn)了這些特殊符號(hào),需要對(duì)這些特殊符號(hào)做處理。比如搜索c++這這個(gè)關(guān)鍵字
由于‘+‘是特殊字符,所以其被編碼成其他格式。再者,搜索漢字時(shí),漢字也會(huì)被重新編碼
雖然url欄顯式的是漢字,但是把url復(fù)制下來(lái)再粘貼,得到的url是
https://www.baidu.com/s?wd=%E5%93%88%E5%93%88
這里說(shuō)明一下特殊字符的編碼規(guī)則,將特殊字符轉(zhuǎn)換成十六進(jìn)制,以兩個(gè)十六進(jìn)制數(shù)為一組,從低到高一次取出每一組,再它們的前面加上%,編碼成%XY的形式。查詢ASCII碼表,+的碼值為43,表示成十六進(jìn)制是2B,所以在url中,其被編碼成%2B
由于url采用的是utf-8編碼格式,在該格式下漢字被編碼成3個(gè)字節(jié),由于兩個(gè)十六進(jìn)制數(shù)表示1個(gè)字節(jié),剛才“哈哈”被編碼后,有6組%XY格式的數(shù)據(jù),也就是6個(gè)字節(jié)。關(guān)于把特殊字符進(jìn)行編碼的過(guò)程,我們叫做urlencode,將%XY格式的數(shù)據(jù)解碼的過(guò)程,我們叫做urldecode
再回過(guò)頭來(lái)看url,其全稱是Uniform Resource Locator,統(tǒng)一資源定位符,通過(guò)url我們就能定位互聯(lián)網(wǎng)上某一臺(tái)主機(jī)的某些資源。我們使用http協(xié)議進(jìn)行請(qǐng)求,就是請(qǐng)求獲取某一天主機(jī)(服務(wù)器)上的某些資源(音視頻,文本),當(dāng)然,服務(wù)器的響應(yīng)就是將客戶端請(qǐng)求獲取的資源返回。所以說(shuō),我們?cè)L問(wèn)的網(wǎng)頁(yè),看到的視頻,文字,不是憑空產(chǎn)生的,這些資源都是存儲(chǔ)在某些服務(wù)器的磁盤上,在我們請(qǐng)求資源時(shí),由服務(wù)器發(fā)送給我們的。
http協(xié)議介紹
比起上篇博客,自己定制的協(xié)議,http協(xié)議能夠使用的場(chǎng)景實(shí)在是太多了,同樣的,關(guān)于http的協(xié)議格式也是更復(fù)雜的
可以看到http協(xié)議格式使用\r\n作為不同字段的分隔符,以http請(qǐng)求為例,在第一個(gè)分隔符之前的數(shù)據(jù)就是http的請(qǐng)求行,里面含有
method:具體http請(qǐng)求的方法,如GET,POST
url:剛才說(shuō)過(guò)的,url用來(lái)定位具體資源
http/1.1:http協(xié)議的版本
在第一行,請(qǐng)求行之后的字段就是請(qǐng)求報(bào)頭,其中可能含有客戶端主機(jī)的信息,連接的屬性,有效載荷的長(zhǎng)度等等信息,這些信息以key:value的格式保存在報(bào)頭中,由于這些字段以\r\n分隔,所以可以直觀的認(rèn)為報(bào)頭的每一行都是一對(duì)key:value信息。繼續(xù)這樣進(jìn)行讀取,我們會(huì)遇到一個(gè)空行,也就是說(shuō)在報(bào)頭的最后一個(gè)key:value后會(huì)有兩個(gè)\r\n,前一個(gè)\r\n用來(lái)分隔最后的key:value字段,那么后一個(gè)key:value是用來(lái)劃分有效載荷與報(bào)頭的,讀取http請(qǐng)求時(shí),如果遇到了一個(gè)空行,就說(shuō)明接下來(lái)的數(shù)據(jù)是這次請(qǐng)求的有效載荷了。客戶端的請(qǐng)求無(wú)非兩種,一是請(qǐng)求獲取服務(wù)端的資源,二是請(qǐng)求將客戶端的資源上傳到服務(wù)端,這些信息都將在有效載荷中體現(xiàn)
至于服務(wù)端的響應(yīng),其格式與客戶端的請(qǐng)求幾乎相同,都是三個(gè)字段:響應(yīng)行,響應(yīng)報(bào)頭,有效載荷。它們的分隔規(guī)則是一樣的,不同的是響應(yīng)行中的數(shù)據(jù)
http/1.1 狀態(tài)碼 狀態(tài)碼描述
可以看到請(qǐng)求和響應(yīng)都含有協(xié)議的具體版本信息,這樣做的目的是:為了使通信能夠正常進(jìn)行,通信雙方要保證通信協(xié)議版本的一致性,所以客戶端和服務(wù)端互相發(fā)送http協(xié)議的版本,如果兩者的版本不同,將按照:以較低版本進(jìn)行通信的原則,進(jìn)行協(xié)議的調(diào)整。響應(yīng)行還包括了狀態(tài)碼和其描述,通常我們請(qǐng)求的網(wǎng)頁(yè)都是能正常訪問(wèn)的,但是也會(huì)有錯(cuò)誤情況出現(xiàn),錯(cuò)誤碼就表征了請(qǐng)求中的錯(cuò)誤,最常見(jiàn)到的錯(cuò)誤碼就是404,如果你要訪問(wèn)的服務(wù)端資源不存在,那么服務(wù)端的狀態(tài)碼將被設(shè)置為404
GET vs POST
http協(xié)議中有很多方法:GET,POST,PUT,DELETE,OPTIONS…其中最經(jīng)常使用的方法是GET,POST,至于其他方法就較為少見(jiàn)了,如果遇到就現(xiàn)學(xué)吧。這里主要說(shuō)明GET和POST的區(qū)別,其中的依據(jù)來(lái)自
HTTP 方法:GET 對(duì)比 POST。首先,GET和POST都是明文傳送,兩者都是不安全的,使用這兩個(gè)方法時(shí),我們的數(shù)據(jù)總是在網(wǎng)絡(luò)上裸奔,只是方式不同罷了
(在之前的博客中,我搭建了一個(gè)TCP網(wǎng)絡(luò)通信模型,由于http協(xié)議是基于tcp的,所以我這里就直接改造這個(gè)模型,實(shí)現(xiàn)一份服務(wù)端代碼,對(duì)瀏覽器(客戶端)的請(qǐng)求做出響應(yīng))
#include <iostream>
#include <string>
#include <stdlib.h>
#include <fstream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>using namespace std;#define CRLF "\r\n"
#define HOME_PAGE "index.html"
#define ROOT_PAGE "wwwroot"
#define SPACE " "string getPath(const string& req)
{// 請(qǐng)求行的獲取size_t head_pos = req.find(CRLF);if (head_pos == string::npos)return "";string head = req.substr(0, head_pos);// 資源路徑的獲取size_t path_start = head.find(SPACE);size_t path_end = head.rfind(SPACE);if (path_start == string::npos || path_end == string::npos)return "";// 獲取資源地址string path = head.substr(path_start + 1, path_end - path_start - 1);// 如果地址為/,默認(rèn)訪問(wèn)家目錄if (path[0] == '/' && path.size() == 1) path += HOME_PAGE;return path;
}string readFile(const string& path)
{ifstream file(path);if (!file.is_open()) return "404";// 將資源的所有數(shù)據(jù)返回string line;string content;// 讀取整份文件的內(nèi)容while (file.peek() != EOF){getline(file, line);content += line;}return content;
}// 先獲取請(qǐng)求報(bào)頭中的資源位置
// 讀取該資源,將其返回
void handlerRequest(int sock)
{char buf[10240] = {0};ssize_t r_ret = read(sock, buf, sizeof(buf));if (r_ret < 0)cout << "read fail" << endl;else if (r_ret == 0)cout << "client quit" << endl;// 讀取成功else{string req_str = buf;// for testcout << req_str << endl;// 獲取請(qǐng)求行中的資源string path = getPath(req_str);// 讀取客戶請(qǐng)求的資源,當(dāng)前根路徑的保存string resource_path = ROOT_PAGE;resource_path += path;// 獲取文件資源string resource = readFile(resource_path);string suffix = "";// 獲取文件的后綴size_t suffix_pos = resource_path.rfind('.');if (suffix_pos != string::npos)suffix = resource_path.substr(suffix_pos);// 創(chuàng)建響應(yīng)string response = "HTTP/1.1 200 OK\r\n";// 根據(jù)后綴為響應(yīng)報(bào)頭添加不同字段if (suffix == ".jpg") response += "Content-type: image/jpeg\r\n";else response += "Content-type: text/html\r\n";// 請(qǐng)求正文長(zhǎng)度字段的添加response += ("Content-Length: " + to_string(resource.size()) + "\r\n");response += "\r\n";// 響應(yīng)正文response += resource;// 向客戶端發(fā)送響應(yīng)write(sock, response.c_str(), response.size());}
}class tcpServer
{
public:tcpServer(uint16_t port, std::string ip = "") : _ip(ip), _port(port) {}~tcpServer() {}void init(){// 創(chuàng)建套接字文件_listen_sockfd = socket(AF_INET, SOCK_STREAM, 0);if (_listen_sockfd < 0){std::cerr << "socket: fail" << std::endl;exit(-1);}// 填充套接字信息struct sockaddr_in local;local.sin_family = AF_INET;local.sin_port = htons(_port);_ip.empty() ? local.sin_addr.s_addr = INADDR_ANY : inet_aton(_ip.c_str(), &local.sin_addr);// 將信息綁定到套接字文件中if (bind(_listen_sockfd, (const struct sockaddr *)&local, sizeof(local)) < 0){std::cerr << "bind: fail" << std::endl;exit(-1);}// 至此,套接字創(chuàng)建完成,所有的步驟與udp通信一樣// 使套接字進(jìn)入監(jiān)聽(tīng)狀態(tài)if (listen(_listen_sockfd, 5) < 0){std::cerr << "listen: fail" << std::endl;exit(-1);}// 套接字初始化完成std::cout << "listen done" << std::endl;}void loop(){// signal(SIGCHLD, SIG_IGN); // 設(shè)置SIGCHLD信號(hào)為忽略,這樣子進(jìn)程就會(huì)自動(dòng)釋放資源// 創(chuàng)建保存套接字信息的結(jié)構(gòu)體struct sockaddr_in peer;socklen_t peer_len = sizeof(peer);// 接受監(jiān)聽(tīng)隊(duì)列中的套接字請(qǐng)求while (true){int server_sockfd = accept(_listen_sockfd, (struct sockaddr *)&peer, &peer_len);if (server_sockfd < 0){std::cerr << "accept: fail" << std::endl;continue;}std::cout << "accept done" << std::endl;// 提取請(qǐng)求方的套接字信息uint16_t peer_port = ntohs(peer.sin_port);std::string peer_ip = inet_ntoa(peer.sin_addr);// 打印請(qǐng)求方的套接字信息std::cout << "accept: " << peer_ip << " [" << peer_port << "]" << std::endl;// 使用孫子進(jìn)程提供服務(wù)// grandparentpid_t id = fork();// 祖父進(jìn)程if (id == 0){// 父進(jìn)程pid_t cid = fork();if (cid > 0){// 關(guān)閉父進(jìn)程exit(1);}// 孫子進(jìn)程,孤兒,由1號(hào)進(jìn)程管理handlerRequest(server_sockfd);}// 阻塞的回收進(jìn)程資源waitpid(id, nullptr, 0);}}
private:std::string _ip;uint16_t _port;int _listen_sockfd;
};static void Usage(std::string proc)
{std::cerr << "Usage:\n\t" << proc << " port" << std::endl;std::cerr << "example:\n\t" << proc << " 8080\n"<< std::endl;
}int main(int argc, char *argv[])
{if (argc != 2){Usage(argv[0]);exit(0);}uint16_t port = atoi(argv[1]);tcpServer svr(port);svr.init();svr.loop();return 0;
}
tcp通信的部分就不再贅述了。為防止僵尸進(jìn)程,該通信模型創(chuàng)建孫子進(jìn)程為客戶端提供服務(wù),而退出子進(jìn)程,使孫子進(jìn)程成為孤兒進(jìn)程,由1號(hào)進(jìn)程負(fù)責(zé)其資源的釋放。服務(wù)端接收到客戶端的請(qǐng)求,會(huì)對(duì)該請(qǐng)求進(jìn)行解析,得到請(qǐng)求需要的資源路徑,服務(wù)端會(huì)將該資源返回給客戶端。下面這份網(wǎng)頁(yè)就是服務(wù)端默認(rèn)返回給用戶的資源
<!-- index.html -->
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>測(cè)試</title>
</head><body><h3>hello my server!</h3><p>我終于測(cè)試完了我的代碼</p><form action="/a/b/c.html" method="get">Username: <input type="text" name="user"><br>Password: <input type="password" name="passwd"><br><input type="submit" value="Submit"></form>
</body></html>
這個(gè)網(wǎng)頁(yè)中有一個(gè)表單,客戶可以提交它們的用戶名和密碼信息,其中action標(biāo)簽表示將這些信息發(fā)送到指定網(wǎng)頁(yè)上(當(dāng)然是客戶端再向服務(wù)端發(fā)送一次請(qǐng)求了),為了測(cè)試簡(jiǎn)單,這里將信息發(fā)送到一個(gè)不存在的網(wǎng)頁(yè)中,我們只觀察GET和POST的區(qū)別。
注意,服務(wù)端接收到客戶端的請(qǐng)求后,會(huì)將客戶端的請(qǐng)求打印出來(lái),方便我們的測(cè)試,在瀏覽器的url中輸入IP:port,訪問(wèn)服務(wù)
我們輸入用戶名123,密碼456,點(diǎn)擊submit按鈕,這些數(shù)據(jù)會(huì)被發(fā)送到action指定的網(wǎng)頁(yè)上,并且方法是get
很正常,因?yàn)榫W(wǎng)頁(yè)不存在,所以返回404。但是我們注意到,輸入的用戶名和密碼在url中以查詢字符串的方式顯示了出來(lái)。
將網(wǎng)頁(yè)提交數(shù)據(jù)的方式修改為post,重新運(yùn)行服務(wù),重新連接到該服務(wù),輸入用戶名密碼,submit
可以看到,用戶名和密碼沒(méi)有在url中體現(xiàn),觀察服務(wù)端打印的客戶端請(qǐng)求,可以看到這些信息出現(xiàn)在請(qǐng)求的正文部分。
總結(jié)一下:GET將數(shù)據(jù)以查詢字符串的方式拼接到url中,而POST將數(shù)據(jù)以正文的方式置于請(qǐng)求中,兩者都是明文傳輸,不同的只是POST較GET更隱蔽一些,但兩者在本質(zhì)上都是不安全的。
http狀態(tài)碼
1xx | 信息狀態(tài)碼Informational | 接收的請(qǐng)求正在處理,由于現(xiàn)在的網(wǎng)絡(luò)響應(yīng)快,這樣的狀態(tài)碼很少使用了 |
---|---|---|
2xx | 成功狀態(tài)碼Success | 請(qǐng)求正常處理完畢 |
3xx | 重定向狀態(tài)碼Redirection | 將請(qǐng)求重定向到其他資源上 |
4xx | 客戶端錯(cuò)誤狀態(tài)碼Client Error | 服務(wù)器無(wú)法處理請(qǐng)求,請(qǐng)求非法 |
5xx | 服務(wù)端錯(cuò)誤狀態(tài)碼Server Error | 服務(wù)端運(yùn)行出錯(cuò) |
這些狀態(tài)碼也不需要具體記憶,記住幾個(gè)常用的就行了,比如200(OK),404(Not Found),403(Forbidden),302(Redirect),504(Bad Gateway,服務(wù)器訪問(wèn)上游服務(wù)器超時(shí))
void for_redirection(int sock)
{char buf[10240] = {0};ssize_t r_ret = read(sock, buf, sizeof(buf));if (r_ret < 0)cout << "read fail" << endl;else if (r_ret == 0)cout << "client quit" << endl;// 讀取成功else{string req_str = buf;// 創(chuàng)建響應(yīng)string response = "HTTP/1.1 302 Moved Temporarily\r\n";// 請(qǐng)求正文長(zhǎng)度字段的添加response += "location: https://baike.baidu.com/item/302/878045?fr=aladdin\r\n";response += "\r\n";// 向客戶端發(fā)送響應(yīng)write(sock, response.c_str(), response.size());}
}
簡(jiǎn)單的,將服務(wù)端的響應(yīng)修改,請(qǐng)求行修改為"HTTP/1.1 302 Moved Temporarily\r\n",然后在報(bào)頭中添加location字段,表示重定向的url,如果服務(wù)端只提供以上服務(wù)的話,不論客戶端向服務(wù)端發(fā)送什么,客戶端都將跳轉(zhuǎn)到location字段的url上。不過(guò)關(guān)于301和302的區(qū)別還是要注意一下的,301是當(dāng)前資源的永久性轉(zhuǎn)移,而302是資源的臨時(shí)性轉(zhuǎn)移。如果收藏夾中,有一個(gè)url301了,瀏覽器可能會(huì)將該url修改為新的url,而302就不會(huì)
http常見(jiàn)header
Content-type:正文數(shù)據(jù)類型(html/text,image/jpeg)
Content-Length:正文長(zhǎng)度
Host:告知服務(wù)端,客戶端要訪問(wèn)的資源在哪臺(tái)主機(jī)上
User-Agenr:聲明用戶的操作系統(tǒng)和瀏覽器版本信息
referer:當(dāng)前頁(yè)面是從哪個(gè)頁(yè)面跳轉(zhuǎn)過(guò)來(lái)了
location:配合3xx使用,指定重定向的url,客戶端將訪問(wèn)該url
Cookie:存儲(chǔ)用戶一些數(shù)據(jù),用來(lái)進(jìn)行會(huì)話的維持
header就是http中的報(bào)頭字段,以上展示的是字段中的key,每一字段以key:value的方式呈現(xiàn)
最后還剩一個(gè)值得講解的header:Connection,http1.0的Connection默認(rèn)為closed,http1.1的Connection默認(rèn)為keep-alive,一個(gè)為短連接一個(gè)為長(zhǎng)連接。在互聯(lián)網(wǎng)發(fā)展早期,網(wǎng)頁(yè)中的信息沒(méi)有現(xiàn)在這么的密集,一次http請(qǐng)求就可以獲取完整的網(wǎng)頁(yè)并呈現(xiàn)給客戶。但是隨著互聯(lián)網(wǎng)的發(fā)展,網(wǎng)頁(yè)中的信息越來(lái)越多,越來(lái)越復(fù)雜,所以一次http協(xié)議無(wú)法獲取完整的網(wǎng)頁(yè),而http是基于tcp通信的,多次http請(qǐng)求就代表這多次tcp的連接,這樣的做法勢(shì)必會(huì)導(dǎo)致網(wǎng)頁(yè)加載速度的下降,由此http/1.1默認(rèn)開(kāi)啟長(zhǎng)連接,只有一個(gè)網(wǎng)頁(yè)的資源請(qǐng)求完成,tcp連接才會(huì)關(guān)閉。關(guān)于長(zhǎng)連接的深入學(xué)習(xí),具體實(shí)現(xiàn)可以閱讀這篇博客
cookie + session
http有一個(gè)特性:無(wú)狀態(tài),即無(wú)法進(jìn)行狀態(tài)的保持,每一次請(qǐng)求都是獨(dú)立的。但在網(wǎng)頁(yè)端瀏覽b站時(shí),登錄賬號(hào)過(guò)后,每次訪問(wèn)b站都會(huì)保持你的登錄信息,其中的原理就與cookie有關(guān)
(上圖來(lái)自網(wǎng)絡(luò))當(dāng)然了,首次登錄b站時(shí),你還是需要輸入你的賬號(hào)密碼的,一旦選擇登錄,瀏覽器就會(huì)將你的用戶信息通過(guò)http協(xié)議傳輸?shù)絙站的服務(wù)端,服務(wù)端認(rèn)證成功,確認(rèn)該賬號(hào)是有效的之后,會(huì)生成一個(gè)cookie文件,并發(fā)送一個(gè)set-Cookie的響應(yīng),使客戶端在磁盤或者內(nèi)存上保持該cookie文件。之后客戶端的http請(qǐng)求就會(huì)攜帶這份cookie文件,服務(wù)端收到cookie文件后進(jìn)行解析,得到有效數(shù)據(jù)認(rèn)證成功之后,才會(huì)將特定的響應(yīng)返回給客戶端,此時(shí)客戶端看到的網(wǎng)頁(yè)就是已經(jīng)登陸賬號(hào)的網(wǎng)頁(yè)了。
如果cookie存儲(chǔ)在磁盤上,那么關(guān)閉瀏覽器,甚至關(guān)機(jī)之后再打開(kāi)該網(wǎng)頁(yè),你的賬號(hào)登錄信息依舊能保持,因?yàn)閏ookie文件在磁盤上,除非你直接刪除,否則該文件會(huì)一直存在。但是cookie文件存儲(chǔ)在內(nèi)存(瀏覽器)中時(shí),關(guān)閉了瀏覽器(注意不是關(guān)閉網(wǎng)頁(yè)),瀏覽器的進(jìn)程資源被釋放,屬于瀏覽器資源的cookie文件當(dāng)然也被釋放,此時(shí)再打開(kāi)瀏覽器,登錄信息就無(wú)法保持。如果只是把網(wǎng)站關(guān)閉,瀏覽器沒(méi)關(guān)閉,再打開(kāi)該網(wǎng)站,登錄信息依舊是能保存的,因?yàn)閏ookie文件沒(méi)有被釋放。
但由于安全性的問(wèn)題,將cookie文件存儲(chǔ)在客戶端的做法。因?yàn)榭蛻舳巳菀自獾焦?#xff0c;或者說(shuō)信息容易泄漏,如果cookie被非法竊取,cookie所有者的權(quán)益將會(huì)受到損害。所以現(xiàn)在主流的策略都是cookie+session,將cookie文件存儲(chǔ)在服務(wù)端(Linux系統(tǒng)安全性極高)。其主要實(shí)現(xiàn)是:客戶端提交登錄信息,服務(wù)端接收后在后臺(tái)數(shù)據(jù)庫(kù)上將這些信息存儲(chǔ)起來(lái),然后生成一個(gè)唯一的id,這個(gè)id可以理解為key,數(shù)據(jù)庫(kù)中存儲(chǔ)的信息可以理解為value,這就是一對(duì)key:value模型。服務(wù)端將id返回給客戶端,使客戶端set-Cookie,將該id值保存起來(lái),此后客戶端的http請(qǐng)求都會(huì)帶上該id值,服務(wù)端收到id后,找到其對(duì)應(yīng)value,就能解析出客戶的信息,也就能根據(jù)這些信息進(jìn)行會(huì)話保持了。
但是cookie+session的方式同樣是不安全的,id值同樣可以被竊取,被非法利用。但是被竊取的只是一個(gè)id值,你的具體信息沒(méi)有得到泄漏,具體信息存儲(chǔ)在服務(wù)端的數(shù)據(jù)庫(kù)中,要攻擊這樣的數(shù)據(jù)庫(kù)還是比較難的。這也是相對(duì)直接使用cookie的優(yōu)勢(shì)吧,或者這么說(shuō),http協(xié)議就是不安全的,它的目的是通信的進(jìn)行,側(cè)重于通信的實(shí)現(xiàn),至于安不安全就是另外一回事了,因此不推薦用http進(jìn)行私密數(shù)據(jù)的傳輸,要進(jìn)行這樣的傳輸可以使用更側(cè)重安全性的https協(xié)議