HTTP
HTTP (全稱為 “超文本傳輸協(xié)議”) 是一種應(yīng)用非常廣泛的 應(yīng)用層協(xié)議。
我們平時(shí)打開一個(gè)網(wǎng)站,就是通過 Http 協(xié)議來傳輸數(shù)據(jù)的。
學(xué)習(xí) Http 需要先了解 http 協(xié)議格式,這里就需要用到 抓包工具。抓包工具本質(zhì)上是一個(gè)代理。
代理:代理是一種網(wǎng)絡(luò)服務(wù),它充當(dāng)客戶端和目標(biāo)服務(wù)器之間的中間人。代理服務(wù)器可以用于多種目的,包括提高訪問速度、保護(hù)隱私、繞過網(wǎng)絡(luò)限制等。
1. 抓包工具的使用
抓包工具有很多,比如:wireshark、fiddler等…
這里我們使用 fiddler 來抓包,同學(xué)們可以自行下載。
1.1 配置信息
在我們剛裝好 fiddler 之后,默認(rèn)只能抓到 http 的數(shù)據(jù),抓不到 https ,而現(xiàn)在網(wǎng)絡(luò)上 https 是主流。因此我們要稍微設(shè)置一下讓 fiddler 能夠抓到 https。
設(shè)置完后,我們可以看到,左側(cè)是當(dāng)前機(jī)器上有哪些 http / https數(shù)據(jù)報(bào)在交互(不僅僅能抓瀏覽器,而且能抓到所有程序的)
當(dāng)我們選中某個(gè)數(shù)據(jù)后,右側(cè)就能顯示出詳細(xì)信息,右上角顯示的是請(qǐng)求的詳情,右下角顯示的是響應(yīng)的內(nèi)容(在標(biāo)簽欄中點(diǎn)擊 Raw 顯示 請(qǐng)求/響應(yīng) 的原始數(shù)據(jù)內(nèi)容)
1.2 觀察數(shù)據(jù)
相比于 UDP、TCP 的二進(jìn)制信息傳輸來說,Http 則是文本傳輸格式。如果看不清藍(lán)色信息欄中的數(shù)據(jù),我們可以點(diǎn)擊下方 View in Notepad 在記事本中打開
觀察下面響應(yīng)信息,為什么會(huì)出現(xiàn)亂碼呢?
在網(wǎng)絡(luò)傳輸過程中,為了節(jié)省空間大小,因此會(huì)對(duì)響應(yīng)信息進(jìn)行壓縮(點(diǎn)擊圖片上面黃色區(qū)域就會(huì)進(jìn)行解壓縮)
2. 分析 https 抓包結(jié)果
下面是一個(gè) HTTPS請(qǐng)求/響應(yīng) 的抓包結(jié)果。
首行組成格式:[方法] + [URL] + [版本];
請(qǐng)求頭(header):是請(qǐng)求的屬性,用冒號(hào)來分割的鍵值對(duì)。每組屬性之間用
\n
來分隔,遇到空行表示 header 部分 結(jié)束。body:空行后面的都是正文(body),body允許為空字符串。如果 body 存在,則在 header 中會(huì)有一個(gè) Conent- ??? Length 屬性來標(biāo)識(shí) Body 的長度。
首行:[版本號(hào)] + [狀態(tài)碼] + [狀態(tài)碼解釋]
響應(yīng)頭:同請(qǐng)求頭。也是由鍵值對(duì)組成,由
\n
分隔。正文:同請(qǐng)求的正文格式。如果服務(wù)器返回了一個(gè) html 頁面,那么 html 頁面內(nèi)容就是在 body 中。
3. HTTP請(qǐng)求詳解
3.1 認(rèn)識(shí) URL
3.1.1 URL 基本格式
URL 的格式通常如下:
協(xié)議://主機(jī)名[:端口號(hào)]/路徑?查詢參數(shù)
實(shí)際上,對(duì)于 URL 來說,上述的幾個(gè)部分都是可以省略的,此操作是非常常見的。
3.1.2 查詢字符串 (query string)
下面舉一個(gè)具體的例子來說明 URL 格式中的查詢字符串。
我們?cè)谒压飞纤阉鳌俺绦蛟场???梢钥吹椒?wù)器是搜狗服務(wù)器。同時(shí)在搜狗服務(wù)器上訪問的是 web 資源。后續(xù)再在資源中查找“程序猿”這個(gè)字符串以及其它字符串。
我們雖然認(rèn)識(shí)了 query string(查詢字符串) 的格式,但其內(nèi)容和含義是什么呢??
其實(shí)是這里的 鍵 和 值 的含義,都是程序猿自定義的。這個(gè)東西具體是啥意思?只有搜狗的程序員知道。
3.1.3 關(guān)于 URL Encode
像 / ? : 等這樣的字符, 已經(jīng)被url當(dāng)做特殊意義理解了。因此這些字符不能隨意出現(xiàn)。
比如,某個(gè)參數(shù)中需要帶有這些特殊字符,就必須先對(duì)特殊字符進(jìn)行轉(zhuǎn)義。
一個(gè)中文字符由 UTF-8 或者 GBK 這樣的編碼方式構(gòu)成, 雖然在 URL 中沒有特殊含義, 但是仍然需
要進(jìn)行轉(zhuǎn)義. 否則瀏覽器可能把 UTF-8/GBK 編碼中的某個(gè)字節(jié)當(dāng)做 URL 中的特殊符號(hào).
轉(zhuǎn)義的規(guī)則如下: 將需要轉(zhuǎn)碼的字符轉(zhuǎn)為16進(jìn)制,然后從右到左,取4位(不足4位直接處理),每2位做一位,前面加上%,編碼成%XY格式。
比如 “+” 被轉(zhuǎn)義成了 “%2B”
UrlEncode - 在線URL網(wǎng)址編碼、解碼
3.2 認(rèn)識(shí) http 方法
上圖中都是http的請(qǐng)求方法,如果說天下文才分十斗,Get就占8斗,Post占1斗,剩下的所有方法占1斗。由此可見各個(gè)方法的使用頻率不同,Get、Post方法作為我們要熟知的方法,剩下的了解即可。
不同方法之間,“語義”是不同的,描述的是此次方法用來干什么。
- Get:“從服務(wù)器獲取 xxx”
- Post:“向服務(wù)器傳輸一個(gè) xxxx”
上面我們介紹過 Get 的請(qǐng)求格式,接下來介紹 Post 的幾個(gè)常見場(chǎng)景:
-
登錄
-
上傳
此處的 body 中的 value 就是把整個(gè)圖片都進(jìn)行轉(zhuǎn)碼,轉(zhuǎn)成字符串,填寫在這里。
3.2.1 [經(jīng)典問題] Get 和 Post 主要的區(qū)別是什么??
Get 是把一些自定義的數(shù)據(jù)放到 query string (在 URL 中) 里,body 通常是空的。
Post 是把一些自定義的數(shù)據(jù)放到 body 里,query string 通常是空的。
因?yàn)檫@些數(shù)據(jù)都是要傳輸給服務(wù)器的,所以放哪都是放,本質(zhì)上沒啥區(qū)別。
- 直接放在 url 中,用戶能直接看到。
- 放在 body 中,用戶沒法直接看到。
因?yàn)?post 和 get 數(shù)據(jù)放哪里本質(zhì)上都可以,兩者經(jīng)常也可以相互替代。
蓋棺定論:GET 和 POST 沒有本質(zhì)區(qū)別。從習(xí)慣上來看,GET 通常把數(shù)據(jù)放到 query string 中,POST 通常把數(shù)據(jù)放到 body 中
對(duì)于 Get 和 Post 區(qū)別的理解。
3.2.2 除了get和post還有什么方法??
? 下面這些方法相較于 get、post 比較少見,可以簡(jiǎn)單了解。
3.3 認(rèn)識(shí)請(qǐng)求報(bào)頭(header)
header 的整體格式也是“鍵值對(duì)”結(jié)構(gòu)。每個(gè)鍵值對(duì)占一行,鍵和值之間使用分號(hào)分割。
以下面的請(qǐng)求報(bào)頭為例,進(jìn)行分析:
可以看到此報(bào)頭也是鍵值對(duì)結(jié)構(gòu),每一行都是一個(gè)鍵值對(duì),鍵和值之間用 “:空格” 來分割。
query string / body 中的鍵值對(duì),完全是程序員自定義的。
header 中的鍵值對(duì),主要是標(biāo)準(zhǔn)規(guī)定的。有哪些鍵(對(duì)應(yīng)的取值是有哪些,都有規(guī)定),也有部分是可以自定義的。
下面來挑幾個(gè)重要的鍵值對(duì)來分析一下:
-
Host
:表示服務(wù)器主機(jī)的地址和端口。(用于解決粘包問題) -
Content-Length
:表示 body 中的數(shù)據(jù)長度 。 -
Content-Type
:表示請(qǐng)求的 body 中的數(shù)據(jù)格式。(針對(duì)這個(gè)數(shù)據(jù),如何理解?http協(xié)議有很多用途,傳輸?shù)臄?shù)據(jù)也有很多種類)在HTTP請(qǐng)求中,Content-Type有三種主要的情況。-
application/x-www-form-urlencoded:body的格式就和query string一樣.(登錄請(qǐng)求)
-
multipart/form-data:一般上傳文件/圖片會(huì)是這種情況(不絕對(duì)。碼云的上傳圖片就不是這種)
-
application/json:body是 json格式。(很多網(wǎng)站都會(huì)廣泛使用 json)
如果是響應(yīng) body,情況就會(huì)更復(fù)雜。
可能是 html:text/html,也可能是 css:text/css,還可能是 js:application/javascript,圖片 image/png image/jpg 等…
通過 Content-Type 就可以區(qū)分出 body 的數(shù)據(jù)的格式是啥。尤其是瀏覽器,需要根據(jù)不同的格式來決定如何處理。
-
-
User-Agent
:表示瀏覽器/操作系統(tǒng)的屬性,現(xiàn)在主要用來區(qū)分 PC 端還是 移動(dòng)端。形如Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36
-
Referer
:**描述了當(dāng)前頁面從哪來。**如果你是通過瀏覽器地址來直接輸入U(xiǎn)RL/點(diǎn)擊收藏夾 打開的網(wǎng)站,這個(gè)請(qǐng)求中不帶 referer。但是如果你點(diǎn)擊了某個(gè)網(wǎng)頁的內(nèi)容,產(chǎn)生跳轉(zhuǎn),就是帶 referer。拓展了解:http由于不帶加密傳輸,因此網(wǎng)絡(luò)運(yùn)營商為了賣廣告或者其他經(jīng)濟(jì)利益,可以直接修改用戶的訪問源頭,就是針對(duì) referer 進(jìn)行修改,此操作稱為運(yùn)營商劫持。解決辦法就是使用https,進(jìn)行加密傳輸。
-
Cookie
:**是瀏覽器本地存儲(chǔ)數(shù)據(jù)的一種機(jī)制。**在用戶操作瀏覽器的時(shí)候會(huì)產(chǎn)生很多“臨時(shí)性”的數(shù)據(jù),有的臨時(shí)數(shù)據(jù)就直接放到服務(wù)器這邊存儲(chǔ),下次可以直接獲取到。有的不太重要的,就直接放在瀏覽器這邊存儲(chǔ)(下次訪問也可以直接使用,但是換個(gè)電腦可能就沒了)其中,Cookie 就是一個(gè)主要的保存機(jī)制。瀏覽器要保存數(shù)據(jù),為啥要放到 Cookie 中??直接放到硬盤,寫入一個(gè)文件不行嗎? 不行的!如果讓網(wǎng)頁能夠輕易的訪問你的文件系統(tǒng),是非常危險(xiǎn)的??!很容易中病毒!
為了保證安全,瀏覽器會(huì)對(duì)網(wǎng)頁的功能做出限制。(禁止直接訪問硬盤,就是其中一個(gè)規(guī)則),同時(shí)又能存儲(chǔ)數(shù)據(jù),瀏覽器就提供了Cookie 功能(后來又有了其他功能)
是按照鍵值對(duì)的方式來存儲(chǔ)一些字符串。這些鍵值對(duì)往往都是服務(wù)器返回回來的。瀏覽器把這些鍵值對(duì)按照"域名"維度,分類存儲(chǔ)。
首次訪問網(wǎng)站,注冊(cè)不考慮,登錄成功之后,就相當(dāng)于,網(wǎng)站就給你了一個(gè)就診卡(身份標(biāo)識(shí) 也叫sessionid)。身份標(biāo)識(shí)就通過服務(wù)器返回給瀏覽器的響應(yīng),保存在瀏覽器的Cookie 中了(鍵值對(duì))。于此同時(shí),人家網(wǎng)站服務(wù)器這邊,也就會(huì)創(chuàng)建出一個(gè)對(duì)應(yīng)的Session (電子檔案)Session 中就會(huì)記錄我的一些關(guān)鍵信息。人家的網(wǎng)站服務(wù)器肯定不只一個(gè)用戶,有很多用戶。每個(gè)用戶都有自己的Session。并且他們的sessionld 各不相同。服務(wù)器就會(huì)使用類似于hash表這樣的方式,以sessionld為key,以Session為value,把所有的數(shù)據(jù)組織起來。
1.Cookie 從哪里來?
Cookie是從服務(wù)器返回給瀏覽器的。2.Cookie 保存在哪里?
Cookie 保存在瀏覽器上,瀏覽器所在電腦的硬盤上。每個(gè)域名都有自己的一組Cookie。3.Cookie里的內(nèi)容是啥?
Cookie 中的內(nèi)容是鍵值對(duì)結(jié)構(gòu)的數(shù)據(jù)。這里的鍵值對(duì)都是程序猿自定義的。
其中往往會(huì)有一個(gè)鍵值對(duì),作為用戶的身份標(biāo)識(shí) (不同網(wǎng)站身份標(biāo)識(shí)的 key 和 value 可能都是不同的)4.Cookie的內(nèi)容到哪里去?
后續(xù)再訪問這個(gè)網(wǎng)站中的各個(gè)頁面,就都會(huì)在請(qǐng)求中帶上Cookie 。服務(wù)器就可以進(jìn)一步的知道客戶端的詳細(xì)情況了。
4. HTTP響應(yīng)詳解
4.1 認(rèn)識(shí)狀態(tài)碼
響應(yīng)的首行和請(qǐng)求的首行差異是比較大的。
響應(yīng)首行由:[版本號(hào)] + [狀態(tài)碼] + [狀態(tài)碼解釋]組成
HTTP/1.1 200 OK
狀態(tài)碼,就是對(duì)這次響應(yīng)的定性(成功/失敗/其它情況)
200成功
404訪問的資源不存在
403訪問的資源沒有權(quán)限
502服務(wù)器掛了
504服務(wù)器超時(shí)了
302重定向(瀏覽器會(huì)自動(dòng)跳轉(zhuǎn)到其他的界面)
重定向:使用瀏覽器訪問 www.aaa.com 這個(gè)url ,此時(shí),請(qǐng)求發(fā)給對(duì)應(yīng)的服務(wù)器。結(jié)果服務(wù)器返回了一個(gè)302,同時(shí)告訴你,你要去訪問 www.bbb.com 于是瀏覽器收到這個(gè)響應(yīng)之后,就會(huì)自動(dòng)跳轉(zhuǎn)到 www.bbb.com。
5. 構(gòu)造 HTTP 請(qǐng)求
5.1 通過 html 中的 form 表單
HTML 也是一種編譯語言,和 Java、C 風(fēng)格差異很大。
HTML:是在描述一個(gè)“形態(tài)”,一個(gè)網(wǎng)頁上,都有啥。(形態(tài))
Java、C:是在描述一個(gè)“邏輯”,先干啥后干啥,什么情況下要干什么。(動(dòng)作)
這里編寫 html 推薦使用 VSCode,因?yàn)榭梢灾苯影祖蔚?,?duì)于前端也同樣支持。
對(duì)于 html 代碼編寫起來是非常好理解的,下面是編寫 html 的起手式,快捷鍵是!+tab
.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 在這里輸入代碼 -->
</body>
</html>
接下來再說通過 html 中的 form 標(biāo)簽構(gòu)造 HTTP 請(qǐng)求。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="https://www.sogou.com" method="post">
<input type="text" name="aaa">
<input type="text" name="bbb">
<input type="text" name="ccc">
<input type="submit" value="提交">
</form>
</body>
</html>
當(dāng)我們運(yùn)行這段代碼,再用抓包工具來抓包觀察結(jié)果。
在輸入框中輸入的內(nèi)容有什么作用嗎?
其實(shí)就是向服務(wù)器提交數(shù)據(jù),比如說我們進(jìn)行用戶登錄,需要輸入的賬號(hào)和密碼。
form 表單,只能支持 get 和 post,不能支持 put/delete/options 等其他方法…
5.2 通過 js 的 ajax
ajax 是 js 提供的一組 api。js 原生的 ajax api,用起來非常不方便。因此我們就會(huì)借助 js 的第三方庫 jQuery,把 jQuery 引入到代碼中。
jQuery cdn
是大佬們搞的一組服務(wù)器,用來放一些常用的資源。
對(duì)于jQuery cdn
來說都是開源的,可以直接在網(wǎng)上搜
只需要把這段復(fù)制下來即可。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script>
//正式的 js 代碼,就要調(diào)用上面的 jQuery 中的方法了。
$.ajax({
type: "post",
url: "https://www.sogou.com",
contentType: "application/x-www-form-urlencoded",
data: "aaa=111&bbb=222",
success:function(body) {
console.log("ok");
}
});
</script>
</body>
</html>
通過抓包可以看到我們?cè)L問的URL、method,以及請(qǐng)求的內(nèi)容。
5.3 java 代碼(其他各種語言的代碼)
通過 java 代碼的方式,本質(zhì)上就是一個(gè) tcp 的客戶端,創(chuàng)建一個(gè) Socket 對(duì)象,往里面按照 HTTP 協(xié)議的格式寫數(shù)據(jù)即可。
public class HttpClient {
private Socket socket;
private String ip;
private int port;
public HttpClient(String ip, int port) throws IOException {
this.ip = ip;
this.port = port;
socket = new Socket(ip, port);
}
public String get(String url) throws IOException {
StringBuilder request = new StringBuilder();
// 構(gòu)造首行
request.append("GET " + url + " HTTP/1.1\n");
// 構(gòu)造 header
request.append("Host: " + ip + ":" + port + "\n");
// 構(gòu)造 空行
request.append("\n");
// 發(fā)送數(shù)據(jù)
OutputStream outputStream = socket.getOutputStream();
outputStream.write(request.toString().getBytes());
// 讀取響應(yīng)數(shù)據(jù)
InputStream inputStream = socket.getInputStream();
byte[] buffer = new byte[1024 * 1024];
int n = inputStream.read(buffer);
return new String(buffer, 0, n, "utf-8");
}
public String post(String url, String body) throws IOException {
StringBuilder request = new StringBuilder();
// 構(gòu)造首行
request.append("POST " + url + " HTTP/1.1\n");
// 構(gòu)造 header
request.append("Host: " + ip + ":" + port + "\n");
request.append("Content-Length: " + body.getBytes().length + "\n");
request.append("Content-Type: text/plain\n");
// 構(gòu)造 空行
request.append("\n");
// 構(gòu)造 body
request.append(body);
// 發(fā)送數(shù)據(jù)
OutputStream outputStream = socket.getOutputStream();
outputStream.write(request.toString().getBytes());
// 讀取響應(yīng)數(shù)據(jù)
InputStream inputStream = socket.getInputStream();
byte[] buffer = new byte[1024 * 1024];
int n = inputStream.read(buffer);
return new String(buffer, 0, n, "utf-8");
}
public static void main(String[] args) throws IOException {
HttpClient httpClient = new HttpClient("42.192.83.143", 8080);
String getResp = httpClient.get("/AjaxMockServer/info");
System.out.println(getResp);
String postResp = httpClient.post("/AjaxMockServer/info", "this is body");
System.out.println(postResp);
}
}
5.4 借助一些第三方工具
除了上面這幾種寫代碼的方式之外,還可以通過第三方工具,構(gòu)造 HTTP 請(qǐng)求。
第三方工具有很多,咱們這里介紹的是 postman,一個(gè)老牌的 http 客戶端工具。他可以根據(jù)你這邊構(gòu)造的請(qǐng)求,自動(dòng)生成代碼。
操作方法:
文章來源:http://www.zghlxwxcb.cn/news/detail-814542.html
自動(dòng)生成代碼:文章來源地址http://www.zghlxwxcb.cn/news/detail-814542.html
到了這里,關(guān)于應(yīng)用層—HTTP詳解(抓包工具、報(bào)文格式、構(gòu)造http等……)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!