header:
header里面的信息, 是給瀏覽器看的, 包括以何種編碼方式解析body等
body:
body里面的信息, 是給用戶看的
HTTP報文:
它是HTTP應用程序之間發(fā)送的數(shù)據(jù)塊。
這些數(shù)據(jù)塊以一些文本形式的元信息開頭淀散,這些信息描述了報文的內(nèi)容及含義右莱,后面跟著可選的數(shù)據(jù)部分。
這些報文都是在客戶端档插、服務器和代理之間流動慢蜓。
HTTP報文的流動方向:
一次HTTP請求,HTTP報文會從“客戶端”流到“代理”再流到“服務器”阀捅,
在服務器工作完成之后胀瞪,報文又會從“服務器”流到“代理”再流到“客戶端”
報文的語法:
所有的HTTP報文都可以分為兩類,請求報文和響應報文。
請求和響應報文的基本報文結構大致是相同的凄诞,只有起始行的語法有所不同圆雁。
1.1請求報文:
它會向Web服務器請求一個動作
請求報文的格式:
起始行: <method> <request-URL> <version>
頭部: <headers>
主體: <entity-body>
1.2響應報文:
它會將請求的結果返回給客戶端。
響應報文的格式:
起始行: <version> <status> <reason-phrase>
頭部: <headers>
主體: <entity-body>
下面是對各部分的簡要描述
1帆谍、請求方法(method):
客戶端希望服務器對資源執(zhí)行的動作
比如伪朽,GET, POST, HEAD, DELETE, OPTIONS, PUT, TRACE
2、請求URL(request-URL):
要直接與服務器進行對話汛蝙,只要請求URL是資源的絕對路徑就可以了烈涮,服務器可以假定自己是URL的主機/端口
3、版本(version):
報文所使用的HTTP版本窖剑。
格式:HTTP/<主要版本號>.<次要版本號>
4坚洽、狀態(tài)碼(status-code):
狀態(tài)碼是三位數(shù)字,描述了請求過程中所發(fā)生的情況西土。
每個狀態(tài)碼的第一位數(shù)字都用于描述狀態(tài)的一般類別(比如讶舰,“成功”、“出錯”等等)
5需了、原因短語(reason-phrase):
數(shù)字狀態(tài)碼的可讀版本跳昼,包含行終止序列之前的所有文本。
原因短語只對人類有意義肋乍,
因此鹅颊,盡管響應行HTTP/1.0 200 NOT OK和HTTP/1.0 200 OK中原因短語的含義不同,
但同樣都會被當作成功指示處理
6墓造、頭部(header):
可以有零個或多個頭部堪伍,
每個首部都包含一個名字,后面跟著一個冒號(:)觅闽,
然后是一個可選的空格杠娱,接著是一個值,
最后是一個CRLF首部是由一個空行(CRLF, Carriage-Return Line-Feed, 回車換行)結束的谱煤,
表示了頭部列表的結束和實體主體部分的開始
7、實體的主體部分(entity-body):
實體的主體部分包含一個由任意數(shù)據(jù)組成的數(shù)據(jù)塊禽拔,
并不是所有的報文都包含實體的主體部分刘离,有時,報文只是以一個CRLF結束睹栖。
2.報文詳解
舉例如下
HTTP報文的組成部分:
對報文進行描述的
1.起始行
2.包含屬性的頭部塊
3.可選的硫惕,包含數(shù)據(jù)的主體部分
2.1起始行
所有的HTTP報文都以一個起始行作為開始。
請求報文的起始行說明了要做些什么野来。
響應報文的起始行說明發(fā)生了什么恼除。
請求報文的起始行:
該行包含了一個方法和一個請求的URL,還包含HTTP 的版本。
響應報文的起始行:
該行包含了響應報文使用的HTTP版本豁辉、數(shù)字狀態(tài)碼令野、原因短語。
2.2頭部
HTTP首部字段向請求和響應報文中添加了一些附加信息徽级。
本質(zhì)上來說气破,它們只是一些key/value的列表。
頭部和協(xié)議配合工作餐抢,共同決定了客戶端和服務器能做什么事情现使。
頭部的分類
2.2.1通用頭部
既可以出現(xiàn)在請求報文中,也可以出現(xiàn)在響應報文中旷痕,它提供了與報文相關的最基本的信息
Connection:允許客戶端和服務器指定與請求/響應連接有關的選項
Date:提供日期和時間標志碳锈,說明報文是什么時間創(chuàng)建的
MIME-Version:給出了發(fā)送端使用的MIME版本
Trailer:如果報文采用了分塊傳輸編碼方式,就可以用這個首部列出位于報文拖掛部分的首部集合
Transfer-Encoding:告知接收端為了保證報文的可靠傳輸欺抗,對報文采用了什么編碼方式
Update:給出了發(fā)送端可能想要“升級”使用的新版本或協(xié)議
Via:顯示了報文經(jīng)過的中間節(jié)點(代理售碳、網(wǎng)關)
Cache-Control:用于隨報文傳送緩存指示
2.2.2請求頭部
請求頭部是只在請求報文中有意義的頭部。
用于說明是誰或什么在發(fā)送請求佩迟、請求源自何處团滥,或者客戶端的喜好及能力
Client-IP:提供了運行客戶端的機器的IP地址
From:提供了客戶端用戶的E-mail地址
Host:給出了接收請求的服務器的主機名和端口號
Referer:提供了包含當前請求URI的文檔的URL
#表明產(chǎn)生請求的網(wǎng)頁來自于哪個URL,用戶是從該 Referer頁面訪問到當前請求的頁面报强。這個屬性可以用來跟蹤Web請求來自哪個頁面灸姊,是從什么網(wǎng)站來的等。
#有時候遇到下載某網(wǎng)站圖片秉溉,需要對應的referer力惯,否則無法下載圖片,那是因為人家做了防盜鏈召嘶,原理就是根據(jù)referer去判斷是否是本網(wǎng)站的地址父晶,如果不是,則拒絕弄跌,如果是甲喝,就可以下載;
UA-Color:提供了與客戶端顯示器的顯示顏色有關的信息
UA-CPU:給出了客戶端CPU的類型或制造商
UA-OS:給出了運行在客戶端機器上的操作系統(tǒng)名稱及版本
UA-Pixels:提供了客戶端顯示器的像素信息
User-Agent:將發(fā)起請求的應用程序名稱告知服務器
Accept:告訴服務器能夠發(fā)送哪些媒體類型
Accept-Charset:告訴服務器能夠發(fā)送哪些字符集
Accept-Encoding:告訴服務器能夠發(fā)送哪些編碼方式
Accept-Language:告訴服務器能夠發(fā)送哪些語言
TE:告訴服務器可以使用那些擴展傳輸編碼
Expect:允許客戶端列出某請求所要求的服務器行為
Range:如果服務器支持范圍請求铛只,就請求資源的指定范圍
If-Match:如果實體標記與文檔當前的實體標記相匹配埠胖,就獲取這份文檔
If-Modified-Sinec:除非在某個指定的日期之后資源被修改過,否則就限制這個請求
If-None-Match:如果提供的實體標記與當前文檔的實體標記不相符淳玩,就獲取文檔
If-Range:允許對文檔的某個范圍進行條件請求
If-Unmodified-Since:除非在某個指定日期之后資源沒有被修改過直撤,否則就限制這個請求
Authorization:包含了客戶端提供給服務器,以便對其自身進行認證的數(shù)據(jù)
Cookie:客戶端用它向服務器傳送數(shù)據(jù)
Cookie2:用來說明請求端支持的cookie版本
Max-Forward:在通往源端服務器的路徑上蜕着,將請求轉(zhuǎn)發(fā)給其他代理或網(wǎng)關的最大次數(shù)
Proxy-Authorization:這個首部在與代理進行認證時使用的
Proxy-Connection:這個首部是在與代理建立連接時使用的
Upgrade-Insecure-Requests (升級為HTTPS請求):
#升級不安全的請求谋竖,意思是會在加載 http 資源時自動替換成 https 請求,讓瀏覽器不再顯示https頁面中的http請求警報。
#HTTPS 是以安全為目標的 HTTP 通道蓖乘,所以在 HTTPS 承載的頁面上不允許出現(xiàn) HTTP 請求锤悄,一旦出現(xiàn)就是提示或報錯。
x-requested-with : XMLHttpRequest (是Ajax 異步請求)
2.2.3響應頭部
響應頭部為客戶端提供了一些額外信息驱敲,
比如誰在發(fā)送響應铁蹈、響應者的功能,甚至與響應相關的一些特殊指令
Age:(從最初創(chuàng)建開始)響應持續(xù)時間
Public:服務器為其資源支持的請求方法列表
Retry-After:如果資源不可用的話众眨,在此日期或時間重試
Server:服務器應用程序軟件的名稱和版本
Title:對HTML文檔來說握牧,就是HTML文檔的源端給出的標題
Warning:比原因短語更詳細一些的警告報文
Accept-Ranges:對此資源來說,服務器可接受的范圍類型
Vary:服務器會根據(jù)這些首部的內(nèi)容挑選出最適合的資源版本發(fā)送給客戶端
Proxy-Authenticate:來自代理的對客戶端的質(zhì)詢列表
Set-Cookie:在客戶端設置數(shù)據(jù)娩梨,以便服務器對客戶端進行標識
Set-Cookie2:與Set-Cookie類似
WWW-Authenticate:來自服務器的對客戶端的質(zhì)詢列表
2.2.4實體首部
描述主體的長度和內(nèi)容沿腰,或者資源自身
Allow:列出了可以對此實體執(zhí)行的請求方法
Location:告知客戶端實體實際上位于何處,用于將接收端定向到資源的位置(URL)上去
Content-Base:解析主體中的相對URL時使用的基礎URL
Content-Encoding:對主體執(zhí)行的任意編碼方式
Content-Language:理解主體時最適宜使用的自然語言
Content-Length:主體的長度
Content-Location:資源實際所處的位置
Content-MD5:主體的MD5校驗和
Content-Range:在整個資源中此實體表示的字節(jié)范圍
Content-Type:這個主體的對象類型
ETag:與此實體相關的實體標記
Expires:實體不再有效狈定,要從原始的源端再次獲取實體的日期和時間
Last-Modified:這個實體最后一次被修改的日期和時間
2.2.5擴展首部
規(guī)范中沒有定義的新首部颂龙,開發(fā)者可以自定義一個首部的key/value
2.3實體的主體部分
該部分其實就是HTTP要傳輸?shù)膬?nèi)容,是可選的纽什。
HTTP報文可以承載很多類型的數(shù)字數(shù)據(jù)措嵌,
比如,圖片芦缰、視頻企巢、HTML文檔電子郵件、軟件應用程序等等让蕾。
2.4HTTP方法
并不是每個服務器都實現(xiàn)了所有的方法浪规。
即使服務器實現(xiàn)了所有這些方法,這些方法的使用很可能也是受限的探孝。
例如笋婿,支持DELETE方法或PUT方法的服務器可能并不希望任何人都能夠刪除或存儲資源,
這些限制通常都是在服務器的配置中進行設置的顿颅。
常用的HTTP方法
GET方法(不包含主體):
通常用于請求服務器發(fā)送某個資源缸濒。
HEAD方法(不包含主體):
與GET方法類似,但服務器在響應中只返回首部粱腻,
使用HEAD方法可以在不獲取資源的情況下了解資源的情況(比如绍填,判斷其類型)溜族;
通過查看響應中的狀態(tài)碼,看看某個對象是否存在丸冕;
通過查看首部粟瞬,測試資源是否被修改了;
POST方法(包含主體):
該方法是用來向服務器發(fā)送數(shù)據(jù)的潦匈,常用于HTML表單
PUT方法(包含主體):
該方法的語義就是讓服務器用請求的主體部分來創(chuàng)建一個由所請求的URL命名的新文檔捺宗,
如果那個URL已經(jīng)存在的話竞端,就用這個主體來替代它萝快。
TRACE方法(不包含主體):
主要用于驗證請求是否如愿穿過了請求/響應鏈
OPTIONS方法(不包含主體):
決定可以在服務器上執(zhí)行那些方法
DELETE方法(不包含主體):
該方法就是請服務器刪除請求URL所指定的資源锻霎,
但是客戶端應用程序無法保證刪除操作一定會被執(zhí)行,
因為HTTP規(guī)范允許服務器在不通知客戶端的情況下撤銷請求
擴展方法:
指的是沒有在HTTP/1.1規(guī)范中定義的方法揪漩,
這些方法為開發(fā)者提供了一種擴展這些HTTP服務能力的手段旋恼。
2.5狀態(tài)碼
HTTP狀態(tài)碼被分成了五大類。狀態(tài)碼為客戶端提供了一種理解事務處理結果的便捷方式奄容。
1冰更、100~199(信息性狀態(tài)碼):
HTTP/1.1向協(xié)議中引入了信息性狀態(tài)碼
2、200~299(成功狀態(tài)碼):
客戶端發(fā)起請求時昂勒,這些請求通常都是成功的蜀细。
服務器有一組用來表示成功的狀態(tài)碼,分別對應于不同類型的請求
3戈盈、300~399(重定向狀態(tài)碼):
重定向狀態(tài)碼要么告知客戶端使用替代位置來訪問他們所感興趣的資源奠衔,
要么就提供一個替代的響應而不是資源的內(nèi)容
4、400~499(客戶端錯誤狀態(tài)碼):
有時客戶端會發(fā)送一些服務器無法處理的東西塘娶。
瀏覽網(wǎng)頁時归斤,我們都看到過臭名昭著的404 Not Found錯誤碼,
這只是服務器在告訴我們刁岸,它對我們請求的資源一無所知
5脏里、500~599(服務器錯誤狀態(tài)碼):
有時客戶端發(fā)送了一條有效請求,服務器自身卻出錯了难捌,這些會返回5xx狀態(tài)碼
3.網(wǎng)絡通信
3.1常見的網(wǎng)絡通信協(xié)議
http協(xié)議
超文本傳輸協(xié)議方案膝宁,除了沒有用戶名和密碼之外,
與通用的URL格式相符根吁,如果省略了端口员淫,就默認為80
基本格式:http://<host>:<port>/<path>?<query>#<frag>
示例:http://www.baidu.com:80/index.html
https協(xié)議
該方案與http方案是一對的,唯一的區(qū)別在于方案https使用了網(wǎng)景的SSL击敌,
SSL為HTTP連接提供了端到端的加密機制介返,其語法與HTTP的語法相同,默認端口為443
基本格式:https://<host>:<port>/<path>?<query>#<frag>
示例:https://www.baidu.com:80/index.html
mailto協(xié)議
mailto URL指向的是E-mail地址沃斤,由于E-mail的行為與其他方案都有所不同圣蝎,
它并不指向任何可以直接訪問的對象
基本格式:mailto:<RFC-822-addr-spec>
示例:mailto:joe@joes-hardware.com
ftp協(xié)議
文件傳輸協(xié)議URL可以用來從FTP服務器上下載或向其上載文件,
并獲取FTP服務器上的目錄結構內(nèi)容的列表
基本格式:ftp:<user>:<password>@<host>:<port>/<path>;<params>
示例:ftp://anonymous:joe%40joes@prep.an.edu:21/pub/gs
rtsp和rtspu協(xié)議
RTSP URL是可以通過實時流傳輸協(xié)議解析的音/視頻媒體資源的標示符衡瓶。
方案respu中的u表示它是使用UDP協(xié)議來獲取資源的
基本格式:rtsp:<user>:<password>@<host>:<port>/<path>
示例:rtspu://www.baidu.com:554/inte/cto_video
file協(xié)議
file方案表示一臺指定主機上可直接訪問的文件徘公。
各字段都遵循通用格式,如果省略了主機名哮针,就默認為正在使用URL的本地主機
基本格式:file:<user>:<password>@<host>:<port>/<path>
示例:file://OFFICE-FS/poli/cds.doc
telnet協(xié)議
telnet方案用于訪問交互式業(yè)務关面,它表示的并不是對象自身坦袍,
而是可通過telnet協(xié)議訪問的交互式應用程式(資源)。
基本格式:telnet://<user>:<password>@<host>:<port>/
示例:telnet:csh:webcsh@joes.com:50/
3.2 ip分類 & port詳解
每一個IP地址包括兩部分:網(wǎng)絡地址和主機地址
3.2.1 A類IP地址
一個A類IP地址由1字節(jié)的網(wǎng)絡地址和3字節(jié)主機地址組成等太,網(wǎng)絡地址的最高位必須是“0”捂齐,
地址范圍1.0.0.1-126.255.255.254
二進制表示為:00000001 00000000 00000000 00000001 - 01111110 11111111 11111111 11111110
可用的A類網(wǎng)絡有126個,每個網(wǎng)絡能容納1677214個主機
3.2.2 B類IP地址
一個B類IP地址由2個字節(jié)的網(wǎng)絡地址和2個字節(jié)的主機地址組成缩抡,網(wǎng)絡地址的最高位必須是“10”奠宜,
地址范圍128.1.0.1-191.255.255.254
二進制表示為:10000000 00000001 00000000 00000001 - 10111111 11111111 11111111 11111110
可用的B類網(wǎng)絡有16384個,每個網(wǎng)絡能容納65534主機
3.2.3 C類IP地址
一個C類IP地址由3字節(jié)的網(wǎng)絡地址和1字節(jié)的主機地址組成瞻想,網(wǎng)絡地址的最高位必須是“110”
范圍192.0.1.1-223.255.255.254
二進制表示為: 11000000 00000000 00000001 00000001 - 11011111 11111111 11111110 11111110
C類網(wǎng)絡可達2097152個压真,每個網(wǎng)絡能容納254個主機
3.2.4 D類地址用于多點廣播
D類IP地址第一個字節(jié)以“1110”開始,它是一個專門保留的地址内边。
它并不指向特定的網(wǎng)絡榴都,目前這一類地址被用在多點廣播(Multicast)中
多點廣播地址用來一次尋址一組計算機 s 地址范圍224.0.0.1-239.255.255.254
3.2.5 E類IP地址
以“1111”開始,為將來使用保留
E類地址保留漠其,僅作實驗和開發(fā)用
3.2.6 私有ip
在這么多網(wǎng)絡IP中嘴高,國際規(guī)定有一部分IP地址是用于我們的局域網(wǎng)使用,也就
是屬于私網(wǎng)IP和屎,不在公網(wǎng)中使用的拴驮,它們的范圍是:
10.0.0.0~10.255.255.255
172.16.0.0~172.31.255.255
192.168.0.0~192.168.255.255
3.2.7 注意
IP地址127.0.0.1~127.255.255.255用于回路測試,
如:127.0.0.1可以代表本機IP地址柴信,用http://127.0.0.1就可以測試本機中配置的Web服務器套啤。
3.2.8 port分類
第一類公認端口(Well Known Ports):
從0到1023,它們緊密綁定(binding)于一些服務随常。
通常這些端口的通訊明確表明了某種服務的協(xié)議潜沦,必須要有Root權限才能綁定。
例如:80端口實際上總是HTTP通訊绪氛。
第二類注冊端口(Registered Ports):
從1024到49151唆鸡。它們松散地綁定于一些服務。
也就是說有許多服務綁定于這些端口枣察,這些端口同樣用于許多其它目的争占。
例如:許多系統(tǒng)處理動態(tài)端口從1024左右開始。
第三類動態(tài)和/或私有端口(Dynamic, private or ephemeral ports):從49152到65535序目。
理論上臂痕,不應為服務分配這些端口。
實際上猿涨,機器通常從1024起分配動態(tài)端口握童。
但也有例外:SUN的RPC端口從32768開始。
4.cookie, session, token
http協(xié)議(包括http2.0)都是無狀態(tài)協(xié)議.
無狀態(tài)是指協(xié)議對于事務處理沒有記憶功能叛赚。
缺少狀態(tài)意味著澡绩,假如后面的處理需要前面的信息片效,
則前面的信息必須重傳,這樣可能導致每次連接傳送的數(shù)據(jù)量增大英古。
另一方面,在服務器不需要前面信息時昙读,應答就較快召调。
直觀地說,就是每個請求都是獨立的蛮浑,與前面的請求和后面的請求都是沒有直接聯(lián)系的唠叛。
實際中的使用情況
在web應用中,我們使用http協(xié)議沮稚,但是我們需要的web是有狀態(tài)的艺沼,
因此加入了cookie、session等機制用于跟蹤用戶的狀態(tài), 從而實現(xiàn)有狀態(tài)的web蕴掏。
4.1cookie
cookie障般,有時也用其復數(shù)形式cookies,
指某些網(wǎng)站為了辨別用戶身份, 進行session跟蹤而儲存在用戶本地終端上的數(shù)據(jù)(通常經(jīng)過加密)盛杰。
cookie是由服務器端生成挽荡,發(fā)送給瀏覽器,
瀏覽器把cookie以kv形式保存到某個目錄下的文本文件內(nèi)即供,
下一次請求同一網(wǎng)站時會把該cookie發(fā)送給服務器定拟。
由于cookie是存在客戶端上的,所以瀏覽器加入了一些限制確保cookie不會被惡意使用逗嫡,
同時不會占據(jù)太多磁盤空間青自,所以每個域的cookie數(shù)量是有限的。
1. cookie是一門客戶端緩存技術
2. cookie數(shù)據(jù)由服務器生成驱证,發(fā)送給瀏覽器保存
3. cookie數(shù)據(jù)的格式:鍵值對
4. cookie數(shù)據(jù)過期機制:設置expire值
4.2session
1.session是一門服務端會話緩存技術延窜。
2.session由服務器端的web容器創(chuàng)建,保存在服務器端雷滚。
3.session保存數(shù)據(jù):鍵值對形式
4.session過期:默認30分鐘
session 從字面上講需曾,就是會話。
這個就類似于你和一個人交談祈远,你怎么知道當前和你交談的是張三而不是李四呢呆万?
對方肯定有某種特征(長相等)表明他就是張三。
session 也是類似的道理车份,服務器要知道當前發(fā)請求給自己的是誰谋减。
為了做這種區(qū)分,服務器就要給每個客戶端分配不同的“身份標識”扫沼,
然后客戶端每次向服務器發(fā)請求的時候出爹,都帶上這個“身份標識”庄吼,
服務器就知道這個請求來自于誰了。
至于客戶端怎么保存這個“身份標識”严就,可以有很多種方式总寻,
對于瀏覽器客戶端,大家都默認采用 cookie 的方式梢为。
服務器使用session把用戶的信息臨時保存在了服務器上渐行,用戶離開網(wǎng)站后session會被銷毀。
這種用戶信息存儲方式相對cookie來說更安全铸董,可是session有一個缺陷:
如果web服務器做了負載均衡祟印,那么下一個操作請求到了另一臺服務器的時候session會丟失。
也就是要解決session共享的問題:
可以另外設計一套專門的session的服務service, 專門用于存儲登錄認證信息, 如redis集群...
但是會有新的問題:
a.每次認證用戶發(fā)起請求時粟害,服務器需要去創(chuàng)建一個記錄來存儲信息蕴忆。
當越來越多的用戶發(fā)請求時,內(nèi)存的開銷也會不斷增加悲幅。
b.可擴展性:在服務端的內(nèi)存中使用Seesion存儲登錄信息套鹅,伴隨而來的是可擴展性問題。
4.3token(防CSRF攻擊)
基于Token的驗證原理
基于Token的身份驗證是無狀態(tài)的夺艰,我們不將用戶信息存在服務器或Session中芋哭。
這種概念解決了在服務端存儲信息時的許多問題
NoSession意味著你的程序可以根據(jù)需要去增減機器,而不用去擔心用戶是否登錄郁副。
基于Token的身份驗證的過程如下
生成的token减牺,客戶端可將token寫入sessionStorage,服務端可將token加密寫入redis集群
1.用戶通過用戶名和密碼發(fā)送請求存谎。
2.程序驗證拔疚。
3.程序返回一個簽名的token 給客戶端。
<!--
為防止有人偽造token, 可以對數(shù)據(jù)做一個簽名既荚,
比如用<HMAC-SHA256>算法稚失,加上一個<密鑰>, 對數(shù)據(jù)做一個簽名,
把這個簽名和數(shù)據(jù)一起作為token, 由于密鑰別人不知道, 就無法偽造token了恰聘。
-->
<!--
服務端不保存token, 當客戶端把這個token發(fā)過來時, 再用同樣的<HMAC-SHA256>算法和同樣的<密鑰>,
對數(shù)據(jù)再計算一次簽名, 和token中的簽名做個比較,
如果相同, 我就知道小F已經(jīng)登錄過了,
如果不相同, 數(shù)據(jù)部分肯定被人篡改過, 我就告訴發(fā)送者: 對不起句各,沒有認證。
-->
<!--
token中的數(shù)據(jù)是明文保存的(雖然可以用Base64做下編碼, 但那不是加密),
還是可以被別人看到的晴叨, 所以不能在其中保存像密碼這樣的敏感信息凿宾。
當然token也可以加密保存!!!
-->
4.客戶端儲存token,并且每次用于每次發(fā)送請求時, 在header中攜帶改token字段。
5.服務器端采用filter過濾器校驗兼蕊。
校驗成功則返回請求數(shù)據(jù)初厚,校驗失敗則返回錯誤碼驗證token并返回數(shù)據(jù)。
每一次請求都需要token孙技。
token應該在HTTP的頭部發(fā)送從而保證了Http請求無狀態(tài)产禾。
我們同樣通過設置服務器屬性Access-Control-Allow-Origin:* 排作,讓服務器能接受到來自所有域的請求。
需要注意的是亚情,在ACAO頭部標明(designating)*時妄痪,不得帶有向HTTP認證,客戶端SSL證書和cookies的證書楞件。
實現(xiàn)思路
app項目為例
一般app項目都會基于一個token做鑒權拌夏。
因為此時客戶端不是瀏覽器,因此就沒有cookie這一說了履因。
當用戶登錄app時,服務器會響應回來一個token信息
(一般都是返回的一串唯一的標識符盹愚,比如說uuid或其他)栅迄。
服務器端會將登錄用戶跟token(票據(jù))保存一個映射關系,
一般保存在redis或者表里面皆怕,服務器端響應回來的token會緩存在手機的本地緩存里毅舆,
后面手機去訪問app的其他頁面,就會帶著這個token去服務器做驗證愈腾,
如果通過這個token能夠從redis找到登錄用戶信息, 那么就認為你是已經(jīng)登錄了的用戶憋活。
Tokens的優(yōu)勢
1.無狀態(tài)、可擴展
在客戶端存儲的Tokens是無狀態(tài)的虱黄,并且能夠被擴展悦即。
基于這種無狀態(tài)和不存儲Session信息,負載負載均衡器能夠?qū)⒂脩粜畔囊粋€服務傳到其他服務器上橱乱。
如果我們將已驗證的用戶的信息保存在Session中辜梳,則每次請求都需要用戶向已驗證的服務器發(fā)送驗證信息(稱為Session親和性)。
用戶量大時泳叠,可能會造成一些擁堵作瞄。但是不要著急。
使用tokens之后這些問題都迎刃而解危纫,因為tokens自己hold住了用戶的驗證信息宗挥。
2.安全性(可先驗證referer,再驗證token)
請求中發(fā)送token而不再是發(fā)送cookie能夠防止CSRF(跨站請求偽造)种蝶。
即使在客戶端使用cookie存儲token契耿,cookie也僅僅是一個存儲機制而不是用于認證。
不將信息存儲在Session中蛤吓,讓我們少了對session操作宵喂。
token是有時效的,一段時間之后用戶需要重新驗證会傲。
我們也不一定需要等到token自動失效锅棕,token有撤回的操作拙泽,
通過token revocataion可以使一個特定的token或是一組有相同認證的token無效。
4.可擴展性
tokens能夠創(chuàng)建與其它程序共享權限的程序裸燎。
例如顾瞻,能將一個隨便的社交帳號和自己的大號(Fackbook或是Twitter)聯(lián)系起來。
當通過服務登錄Twitter(我們將這個過程Buffer)時德绿,我們可以將這些Buffer附到Twitter的數(shù)據(jù)流上荷荤。
使用tokens時,可以提供可選的權限給第三方應用程序移稳。
當用戶想讓另一個應用程序訪問它們的數(shù)據(jù)蕴纳,我們可以通過建立自己的API,得出特殊權限的tokens个粱。
5.多平臺跨域
我們提前先來談論一下CORS(跨域資源共享)古毛,對應用程序和服務進行擴展的時候,需要介入各種各種的設備和應用程序都许。
<Access-Control-Allow-Origin: *>
4.4cookie與session有什么區(qū)別
1)session是服務器端保存用戶信息稻薇,cookie是在客戶端保存用戶信息。
2)session中保存的是對象胶征,cookie保存的是字符串塞椎。
3)session對象隨會話結束而關閉,cookie可以長期保存在客戶端
4)cookie通常用于保存不重要的用戶信息睛低,重要的信息使用session保存案狠。
一些反對意見
http://www.reibang.com/p/af8360b83a9f
5.接口冪等性
什么是冪等性
Methods can also have the property of “idempotence” in that
(aside from error or expiration issues)
the side-effects of N > 0 identical requests is the same as for a single request.
#在分布式集群環(huán)境中提供對外冪等性的接口:
只要調(diào)用接口成功,外部對接口的多次調(diào)用得到的結果是相同的钱雷。
即執(zhí)行多次和一次的效果是一樣的莺戒。
冪等性, 通俗的說就是一個接口, 多次發(fā)起同一個請求, 必須保證操作只能執(zhí)行一次,比如:
>>訂單接口, 不能多次創(chuàng)建訂單
>>支付接口, 重復支付同一筆訂單只能扣一次錢
>>支付寶回調(diào)接口, 可能會多次回調(diào), 必須處理重復回調(diào)
>>普通表單提交接口, 因為網(wǎng)絡超時等原因多次點擊提交, 只能成功一次
什么情況下需要保證冪等性
GET、HEAD急波、OPTIONS和TRACE方法被定義成安全的从铲,它們只是為了獲取數(shù)據(jù),
多個相同請求時服務器端的表現(xiàn)是相同的澄暮,所以它們是天然冪等的名段。
PUT和DELETE方法被定義為冪等的。需要注意了泣懊。
以SQL為例伸辟,有下面三種場景,只有第三種場景需要開發(fā)人員使用其他策略保證冪等性:
>>SELECT col1 FROM tab1 WHER col2=2馍刮,無論執(zhí)行多少次都不會改變狀態(tài)信夫,是天然的冪等。
>>UPDATE tab1 SET col1=1 WHERE col2=2,無論執(zhí)行成功多少次狀態(tài)都是一致的静稻,因此也是冪等操作警没。
>>UPDATE tab1 SET col1=col1+1 WHERE col2=2,每次執(zhí)行的結果都會發(fā)生變化振湾,這種不是冪等的杀迹。
解決方案
###推薦方案: 結合redis與mysql的unique key
要求是支付一個訂單,必須插入一條支付流水押搪,order_id建一個唯一鍵树酪,unique key
所以你在支付一個訂單之前,先插入一條支付流水大州,order_id就已經(jīng)進去了
你就可以寫一個標識到redis里面去续语,set order_id payed,下一次重復請求過來了厦画,
先查redis的order_id對應的value绵载,如果是payed就說明已經(jīng)支付過了,你就別重復支付了
你再重復支付這個訂單的時候苛白,你寫嘗試插入一條支付流水,
數(shù)據(jù)庫給你報錯了焚虱,說unique key沖突了购裙,整個事務回滾就可以了
來保存一個是否處理過的標識也可以,服務的不同實例可以一起操作redis鹃栽。
### 1.樂觀鎖
如果只是更新已有的數(shù)據(jù)躏率,沒有必要對業(yè)務進行加鎖,
設計表結構時使用樂觀鎖民鼓,一般通過version來做樂觀鎖薇芝,
這樣既能保證執(zhí)行效率,又能保證冪等丰嘉。例如:
UPDATE tab1 SET col1=1,version=version+1 WHERE version=#version#
不過夯到,樂觀鎖存在失效的情況,就是常說的ABA問題饮亏,
如果version版本一直是自增的就不會出現(xiàn)ABA的情況耍贾。
### 2.防重表
使用訂單號orderNo做為去重表的唯一索引,每次請求都根據(jù)訂單號向去重表中插入一條數(shù)據(jù)路幸。
第一次請求查詢訂單支付狀態(tài)荐开,當然訂單沒有支付,進行支付操作简肴,無論成功與否晃听,
執(zhí)行完后更新訂單狀態(tài)為成功或失敗,刪除去重表中的數(shù)據(jù)。
后續(xù)的訂單因為表中唯一索引而插入失敗能扒,則返回操作失敗佣渴,直到第一次的請求完成(成功或失敗)赫粥。
可以看出防重表作用是加鎖的功能观话。
### 3.分布式鎖
這里使用的防重表可以使用分布式鎖代替,比如Redis越平。
訂單發(fā)起支付請求频蛔,支付系統(tǒng)會去Redis緩存中查詢是否存在該訂單號的Key,
如果不存在秦叛,則向Redis增加Key為訂單號晦溪。
查詢訂單支付已經(jīng)支付,如果沒有則進行支付挣跋,支付完成后刪除該訂單號的Key三圆。
通過Redis做到了分布式鎖,只有這次訂單訂單支付請求完成避咆,下次請求才能進來舟肉。
相比去重表,將放并發(fā)做到了緩存中查库,較為高效路媚。
思路相同,同一時間只能完成一次支付請求樊销。
### 4.token令牌
這種方式分成兩個階段:申請token階段和支付階段整慎。
第一階段,在進入到提交訂單頁面之前围苫,需要訂單系統(tǒng)根據(jù)用戶信息向支付系統(tǒng)發(fā)起一次申請token的請求裤园,
支付系統(tǒng)將token保存到Redis緩存中,為第二階段支付使用剂府。
第二階段拧揽,訂單系統(tǒng)拿著申請到的token發(fā)起支付請求,支付系統(tǒng)會檢查Redis中是否存在該token腺占,
如果存在强法,表示第一次發(fā)起支付請求,刪除緩存中token后開始支付邏輯處理湾笛;
如果緩存中不存在饮怯,表示非法請求。
實際上這里的token是一個信物嚎研,支付系統(tǒng)根據(jù)token確認蓖墅,你是你媽的孩子库倘。
不足是需要系統(tǒng)間交互兩次,流程較上述方法復雜论矾。
### 5.支付緩沖區(qū)
把訂單的支付請求都快速地接下來教翩,一個快速接單的緩沖管道。
后續(xù)使用異步任務處理管道中的數(shù)據(jù)贪壳,過濾掉重復的待支付訂單饱亿。
優(yōu)點是同步轉(zhuǎn)異步,高吞吐闰靴。
不足是不能及時地返回支付結果彪笼,需要后續(xù)監(jiān)聽支付結果的異步返回。
###狀態(tài)機冪等
在設計單據(jù)相關的業(yè)務蚂且,或者是任務相關的業(yè)務配猫,肯定會涉及到狀態(tài)機(狀態(tài)變更圖),
就是業(yè)務單據(jù)上面有個狀態(tài)杏死,狀態(tài)在不同的情況下會發(fā)生變更泵肄,一般情況下存在有限狀態(tài)機,
這時候淑翼,如果狀態(tài)機已經(jīng)處于下一個狀態(tài)腐巢,這時候來了一個上一個狀態(tài)的變更,理論上是不能夠變更的玄括,
這樣的話冯丙,保證了有限狀態(tài)機的冪等。
注意:訂單等單據(jù)類業(yè)務惠豺,存在很長的狀態(tài)流轉(zhuǎn),一定要深刻理解狀態(tài)機风宁,對業(yè)務系統(tǒng)設計能力提高有很大幫助 洁墙。
冪等性接口的不足
增加了額外控制冪等的業(yè)務邏輯,復雜化了業(yè)務功能戒财;
把并行執(zhí)行的功能改為串行執(zhí)行热监,降低了執(zhí)行效率。
因此除了業(yè)務上的特殊要求外饮寞,盡量不提供冪等的接口孝扛。
參考資源
http://www.reibang.com/p/37cad53375db
http://www.reibang.com/p/3fc3646fad80