https://blog.csdn.net/qq_41079177/article/details/82933744
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Overview
自己總結的太短少,直接放上大佬總結的
Accept:
例:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8
表示客戶端支持的數據格式,或者說客戶端“希望”接受到的內容類型。
這里只是希望,但是服務器具體返回什么樣的內容類型,還是由服務器自己決定,但是無論服務器返回什么樣的內容類型,客戶端都會接收響應報文,不可能說因為內容類型不同,接收不到服務器響應報文,這不符合http協議規范。
我們通過瀏覽器發起get或post請求,該字段都是瀏覽器自動添加的,同樣在服務器端也不會解析該字段的值;
通過ajax請求或其他手段,我們可以設置該字段的值,但是通常也不進行設置。
該字段的應用場景可以是這樣的,有兩個終端,比如一個是純文本閱讀器,如Kinder(不能顯示圖片),另一個是移動終端(可以播放圖片和視頻),均向服務器請求有關“斑馬”的信息,那么這時候服務器端就需要判斷什么樣的終端應該返回什么樣的信息,那么它就可以根據Accept的信息來進行判斷,如果解析到的Accept的值為“text/plain”,那么就表示客戶端只支持文本類型;如果向上面例子中的那樣,則表示客戶端文本圖片視頻都可以。如果我們不加判斷,當返回給文本閱讀器一張圖片時,可能它顯示的就是亂碼。
Accept-Encoding:
例:
Accept-Encoding:gzip, deflate, br
表示客戶端所支持的解碼(解壓縮)格式。
網路數據的傳輸都是占據帶寬的,而將文件數據壓縮能夠降低數據量,減少傳輸時間。所以服務器在返回數據給客戶端時,常常對數據進行壓縮(對用戶透明,通常由服務器或代理來做),而壓縮的方式有多種,到底采用哪一種則需要看客戶端支持哪種解碼方式,這時候就可以根據header中Accept-Encoding的值。
文件或數據的壓縮,由服務器或代理來做,一般不需要程序員干預;客戶端接收到數據時解壓縮,通常由瀏覽器自動完成,對用戶透明。
對於我們主動發起的ajax請求,一般數據量較少,不需要設置該字段。
Accept-Language:
例
Accept-Language:zh-CN,zh;q=0.9
表示客戶端支持的語言格式(不是編碼格式),如中文/英文,通常瀏覽器直接發起請求時,瀏覽器會根據被設置的語言環境(默認語言),來附加上該字段。
一般我們服務器解析報文時,是不理會該字段的。
他的使用場景可以是這樣的,假如有個文件,有各種語言的版本,這樣當不同請求發來時,我們可以根據Accept-Language的值來判斷到底返回哪種語言版本給客戶端。
(其實這種應用場景也一般不采用判斷Accept-Language字段的方法,不靠譜,還不如直接在url中體現語言版本呢)
Accept-Charset:
例:
Accept-Charset:gbk,utf-8;q=0.8
表示客戶端支持編碼格式。服務器在返回報文時,需要將字符按照一定的編碼格式轉換為字節序列發送給客戶端,那么該采用哪種編碼格式呢?
當然作為服務器端,他可以采用任何一種編碼方式,客戶端都得完完整整的接收響應報文。因為目前客戶端幾乎都支持常見編碼類型,所以服務器在返回數據時,只需要按照既定的編碼方式編碼,然后在響應報文中告知客戶端所使用的編碼方式。這樣客戶端在接收到報文后按照該方式進行解碼,就就不會出現亂碼問題。
但是,如果客戶端已經定了就使用某種解碼方式,那么這時候服務器端就不能那么任性了,他就需要解析Accept-Charset字段,根據這個值,來設定采用的編碼方式。
如上例中,以逗號分隔,客戶端支持兩種編碼方式,gbk和utf-8(gbk優先級高於utf8),其中utf-8后的q值,表示utf-8占的“權重”。
題外話:
服務器端怎么通知瀏覽器所采用的編碼格式呢?
如果不通知瀏覽器,那么瀏覽器會采用什么樣的格式解碼呢?
服務器端以原生的Servlet & JSP為例:
1)當返回的是HTML頁面,那么頁面meta charset就指定了編碼格式
2)當返回的是JSP頁面,那么頁面pageEncoding就指定了編碼格式
3)當通過resp的Outputstream返回原生內容時,我們可以通過設置響應頭content-type/content-charset字段來指定編碼格式
那么如果服務器不指定編碼格式呢?
我的測試環境為win10中文操作系統,瀏覽器:Chrome 64.0.3282.186(正式版本)
1)返回的html頁面不設置meta標簽,但是文件本身是utf-8或gbk編碼,中文不亂碼,
服務器會將html頁面轉換為字節流寫給瀏覽器,瀏覽器讀取字節流,由於找不到meta標簽設置的文件格式,就會按照默認的格式解碼。
這時出現的情況是,當原頁面是gbk編碼時,瀏覽器能正常顯示頁面;當原頁面是utf-8編碼時,瀏覽器顯示中文亂碼。
這說明當前Chrome瀏覽器的默認編碼格式為gbk。使用微軟自帶的Microsoft Edge測試結果一樣 。
2)返回JSP頁面時,必須指定pageEncoding。
3)通過response的輸入流,直接返回生成的字節流(GBK格式的),此時,不設置響應頭的編碼格式。
-
@ Override
-
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-
-
//resp.setContentType("text/html;charset=gbk");
-
resp.setContentType( "text/html;");
-
ServletOutputStream out = resp.getOutputStream();
-
out.write("<h1>好好學習</h1>".getBytes("gbk"));
-
out.close();
-
-
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
1、直接在瀏覽器地址欄輸入訪問地址,不亂碼
2、通過ajax發送get請求,亂碼
-
var xhr = new XMLHttpRequest();
-
xhr.onload = function (argument) {
-
if(xhr.readyState==4){
-
alert(xhr.responseText); //打印接收的字符串
-
}
-
}
-
xhr.open( 'get','http://localhost:8080/mvctest/http',true);
-
xhr.send( null);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
當服務器使用gbk編碼返回字節流時,地址欄的http請求不亂碼,但是ajax請求響應亂碼;
如果我們的服務器使用utf-8返回字節流時,地址欄的http請求亂碼,但是ajax不亂碼。
(第二種測試結果貼圖省略)
這說明同一個瀏覽器,在不同的地方采用的編碼格式不同,當瀏覽器解析頁面時,它默認使用的是gbk編碼(可能因為我們的中文操作系統,同時是中文版的軟件,所以瀏覽器默認使用gbk格式來解析頁面);當瀏覽器使用內核XMLHttpRequest對象來解析響應時,默認采用的是utf-8(這個應該跟操作系統語言沒關系,內核層面的應該在哪個國家都一樣)
所以,如果為了確保在各種情況下都不亂碼,服務器一定要通知客戶端所采用的編碼格式
我們繼續來說頭字段的含義:
Referer:
例:
Referer:http://localhost:8080/test/11.html
表示當前請求是從哪個資源發起的;或者是請求的上一步的地址。
我在11.html頁面發起一個請求,這時候瀏覽器封裝的請求頭就有上例中的referer字段,表示當前請求是這個資源鏈接中發起的。
Referer是常用於網站的訪問統計,比如我在很多地方都做了廣告鏈接到我網站的主頁,這時候我就可以通過Referer來查看哪些地方跳轉過來的人多,就說廣告的效果好。
另外,Referer還經常用於防盜鏈,具體可以參見這位兄台博客“http防盜鏈”
If-Modified-Since:
例:
If-Modified-Since:Thu, 29 Mar 2018 08:37:45 GMT
表示客戶端緩存文件的時間。字面翻譯的意思是,“如果從…時間改變了”(就請再發送給我一遍新的文件)。
當客戶端訪問服務器的靜態文件時,通常會將資源結果緩存下來,並標記一下文件的緩存時間(根據響應頭中的Last-Modified字段);當接下來再發送同樣的請求時,會在請求頭中添加上這個字段If-Modified-Since;
服務器端讀取字段值,判斷服務器端文件的最后修改時間,如果如果不晚於該值,說明瀏覽器緩存的文件是最新的,然后就不會重新發送文件內容,而是將相應報文的狀態設置為304,表示你讀取緩存的文件就可以了,這就很大程度上節省了帶寬。
第一次請求頭:
-
GET /mvctest/11.html HTTP/1.1
-
Host: localhost: 8080
-
Connection: keep-alive
-
Upgrade-Insecure-Requests: 1
-
User-Agent: Mozilla/ 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
-
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
-
Accept-Encoding: gzip, deflate, br
-
Accept-Language: zh-CN,zh;q= 0.9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
第一次響應頭:
第二次請求頭:
第二次響應頭:
需要說明的是,If-Modified-Since字段的值,為服務器端文件最后修改的時間,不是請求的訪問時間,時間值為GMT格林尼治時間,不是本地時間。
瀏覽器一般只對.html,.jpg,.css,.js等這些靜態資源進行緩存,對於jsp頁面以及ajax請求的動態結果,不緩存。服務器如Tomcat會自動給靜態文件的響應報文添加“Last-Modified”字段,同時解析請求報文中的If-Modified-Since字段,這些都是對我們透明的。
例如,我們將11.html改為11.jsp,那么瀏覽器將不會緩存頁面內容,服務器每次都響應一個完整的頁面內容給客戶端,也不會在響應報文中添加“Last-Modified”字段。
每次對於JSP請求的響應結果:
If-None-Match:
例:
If-None-Match:W/”607-1522312665174”
該字段同If-Modified-Since字段一樣,都是用來表示資源文件是否是最新的。只不過If-Modified-Since的值為文件的最后修改時間,而該值為資源實體的哈希值,同樣是由服務器生成的。
從上面的截圖中我們可以看到:
第一次請求時,服務器的響應報文中有字段Etag,這就是實體的哈希值,瀏覽器會緩存文件並記錄該值。
第二次請求時,請求頭字段中就有If-None-Match,值為Etag的值,而服務器會判斷該值與服務器中文件的哈希值是否相同,如果相同,就返回304,讓瀏覽器讀取緩存;否則會返回新的資源文件,並在響應頭中設置新的Etag值。
Last-Modified/If-Modified-Since 和 Etag/If-None-Match這兩對頭字段都是來標記緩存資源的,但是后者的優先級要高於前者。
Cache-Control:
例:
Cache-Control:no-cache
字段的字面意思為“緩存-控制”,前面我們將了幾個字段表面客戶端/服務器如何使用緩存機制,而這個字段就是用來控制緩存的。
Cache-Control在請求/響應報文頭中均可設置,分別表明不同的意思,下面我們以響應報文為例:cache-control在響應報文的的取值可以為:public、private、no-cache、no- store、no-transform、must-revalidate、proxy-revalidate、max-age。
所代表的意思為:
其中,no-cache、no-store、max-age為常用的取值。
比如,服務器在響應報文中添加Cache-Control:no-store,表示瀏覽器或各級代理,不要緩存本次的相應內容(即使響應報文中有Etag和Last-Modified);
比如,響應報文中有Cache-Control:no-cache,表示瀏覽器可以緩存響應文件,但是在使用緩存之前,必須通過令牌(Etag)來與服務器進行溝通確認緩存有效。
比如,響應報文中有Cache-Control:max-age=500,表示在接下來的500秒內,瀏覽器可以自主使用緩存內容,不需要向服務器發送同樣的請求。
在請求報文中,也可以添加cache-control字段,其取值可以為no-cache、no-store、max-age、 max-stale、min-fresh、only-if-cached。
客戶端在發送請求到服務器時,可能會經過很多層代理,而這些代理可能就緩存了本次請求想要的文件,而請求中的cache-control就可以控制,是否使用代理中的緩存文件。
比如,請求報文頭中有cache-control:no-cache,那就表示,代理如果返回給我緩存文件時,需要到服務器端進行確認,緩存是不是最新的。
比如,請求報文頭中有cache-control:no-store,那就表示,我不需要代理中的緩存文件,我需要直接請求服務器。
所以我們可以看到,cache-control就是用來控制緩存使用的,如是否緩存,是否使用緩存,緩存到期時間等,而Last-Modified/If-Modified-Since 和 Etag/If-None-Match是標識C/S之間怎么使用緩存。
緩存的使用都是服務器和客戶端的默認行為,對用戶和程序員的透明的,當然我們可以通過配置文件或程序修改他們的行為規則。
附:http協議中對緩存的說明
User-Agent:
例:
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
表示客戶端的軟件環境。如上可以看出使用的是Window10 64位操作系統,Chrome瀏覽器等信息。服務器可以根據該字段評估客戶端的環境從而給出不同的響應。(比如根據請求是從手機端或是電腦端發起的,返回不同版本的頁面)
Host:
例:
Host:localhost:8080
表示請求者的主機地址(IP地址)和端口號。
服務器端可以根據該字段進行ip過濾等操作。
響應頭
Etag、Last-Modified、cache-control在前文中已經說明。
Content-Length:
例:
Content-Length:607
表示接收到的響應報文的總長度為607。
根據這個長度,客戶端可以更准確的接收和解析報文內容。或者可以根據當前接收/解析的長度占總長度的百分比,做出進度條的效果。
Accept-Ranges:
例:
Accept-Ranges:bytes
表示服務器支持http中的Range功能,能夠分段請求客戶端能夠分段請求服務器。
我們上網時常用的“斷點續傳”,或者服務器所謂的“多線程下載”就是靠的服務器端的Range技術。
Range功能的請求-響應流程如此:
客戶端發起帶range的請求:
-
GET /test.rar HTTP/1.1
-
Connection: close
-
Host: 116.1.219.219
-
Range: bytes= 0-100
- 1
- 2
- 3
- 4
在頭中添加Range字段,表示我要請求[0-100]這101個字節的數據。
此處Range的值,可以添加多個片段,如 Range:bytes=0-100,200-300等。
服務器響應報文:
-
HTTP/ 1.1 206 OK
-
Content-Length: 801
-
Content-Type: application/octet-stream
-
Content-Location: http: //www.onlinedown.net/hj_index.htm
-
Content-Range: bytes 0-100/2350 //2350:文件總大小
-
Last-Modified: Mon, 16 Feb 2009 16:10:12 GMT
-
Accept-Ranges: bytes
-
ETag: "d67a4bc5190c91:512"
-
Date: Wed, 18 Feb 2009 07:55:26 GMT
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
響應報文中有Content-Range字段,表示響應的報文片段內容范圍,已經總的數據大小。
同時Range請求的正常的返回碼是206,不是200。
而即使我們請求的不是Range功能請求,那么服務器的返回字段中會有Accept-Range,表示服務器支持Range功能。
Server:
例:
Server: Apache/2.4.1 (Unix)
表示服務器的名稱,是Unix下的Apache服務器