HTTP協(xié)議是一個應(yīng)用層的通信規(guī)范: 雙方要進(jìn)行通信, 大家都要遵守一個規(guī)范——HTTP協(xié)議。HTTP協(xié)議從WWW服務(wù)器傳世超文本到瀏覽器, 可以使瀏覽器更加高效。
HTTP(Hyper Text Transfer PRotocol, 超文本傳輸協(xié)議) 是萬維網(wǎng)協(xié)會(Word Wide Web Consortium) 和Internet 工作小組(Internet Engineering Task Force, IETF) 合作的結(jié)果, 最終發(fā)布了一些列的RFC(Request For Comments)。RFC 1945定義了HTTP 1.0版本, 最著名的RFC 2616, 其中定義了目前普遍使用的版本——HTTP1.1。
HTTP是一個應(yīng)用層協(xié)議, 由請求和響應(yīng)構(gòu)成, 是一個標(biāo)準(zhǔn)的客戶端服務(wù)器模型。HTTP通常承載于TCP協(xié)議之上, 也有時候承載在TLS或SSL協(xié)議層之上, 這個時候就成了常說的HTTPS。
HTTP默認(rèn)端口為80, HTTPS的端口是443。
HTTP協(xié)議是一個無狀態(tài)的協(xié)議, 同一個客戶端的這次請求和上次請求沒有對應(yīng)關(guān)系。
sequenceDiagramClient->>Server: 請求Server->>Client: 響應(yīng)這種設(shè)計屬于問答式交互, 客戶端和服務(wù)器一問一答, 使HTTP協(xié)議模型異常簡單。但是這種設(shè)計也存在一些問題, 例如服務(wù)端不會主動向客戶端PUSH, 一問一答的輪詢也會使TCP連接頻繁建立和斷開, 導(dǎo)致其交互效率不高。基于上面缺點, SPDY協(xié)議誕生了。
SPDY 協(xié)議由谷歌推出, 優(yōu)化瀏覽器和服務(wù)器之間的通信, 支持流復(fù)用, 具備優(yōu)先級的請求、主動發(fā)起請求、強制SSL安全傳輸?shù)认冗M(jìn)特性。
目前Chrome 和 Firefox瀏覽器的最新版本都支持 SPDY, 一些服務(wù)端軟件支持SPDY, 如Jetty 8、Nginx 1.3.x等。
SPDY 協(xié)議的應(yīng)用需要客戶端瀏覽器和服務(wù)端同時支持。 目前應(yīng)用SPDY 協(xié)議主要是Google的產(chǎn)品, 如Google Plus。
瀏覽網(wǎng)頁是HTTP協(xié)議的主要應(yīng)用, 但是不代表HTTP協(xié)議只能用于網(wǎng)頁的瀏覽。只要通信的雙方都遵守HTTP協(xié)議, 就有用武之地。
HTTP協(xié)議如何工作:
首先, 客戶端發(fā)送一個請求(Request) 給服務(wù)器, 服務(wù)器在接收到這個請求后將生成一個響應(yīng)(Response)返回給客戶端。一次HTTP操作稱之為一個事務(wù), 其工作過程可分為四步:
客戶端與服務(wù)器建立連接。點擊某個超鏈接, HTTP 協(xié)議開始工作建立連接后, 客戶機發(fā)送一個請求給服務(wù)器。格式為: 前面是統(tǒng)一資源標(biāo)識符(URL)、中間是協(xié)議版本號、后面是MIME信息(包括請求修飾符、客戶機信息和可能的內(nèi)容)服務(wù)器接到請求后, 給予相應(yīng)的響應(yīng)信息。格式為: 首先是一個狀態(tài)行(包括信息的協(xié)議版本號、一個成功或錯誤的代碼), 然后是MIME信息(包括服務(wù)器信息、實體信息和可能的內(nèi)容)客戶端接收服務(wù)器返回的信息并顯示在用戶顯示屏上, 然后斷開與服務(wù)器的連接關(guān)于HTTP協(xié)議, 可以查看RFC 2616文檔。
常用的抓包軟件有IRIS、Wireshark等。
請求
在發(fā)起請求前, 需要先建立連接。
連接是一個傳輸層的實際環(huán)流, 它建立在兩個相互通信的應(yīng)用程序之間。
HTTP 1.1協(xié)議中, Request 和 Response 頭中都可能出現(xiàn)一個 connection 的頭, 其決定 Client和Server通信時對于長鏈接如何處理。
HTTP 1.1 中, Client和Server默認(rèn)對方支持長鏈接, 如果CLient不希望使用長鏈接, 需要在Header中指明connection 為 cliose; 如果Server 不想支持長鏈接, 則在response中需要明確說明connection 為close。
響應(yīng)
在接收和解釋請求消息后, 服務(wù)器返回一個HTTP響應(yīng)消息。HTTP響應(yīng)也由三個部分組成: 狀態(tài)行、消息報頭、響應(yīng)正文。
狀態(tài)碼由三位數(shù)字組成, 第一個數(shù)字定義了響應(yīng)的類別, 有五種可能取值:
1xxx: 指示信息——請求已被成功接收, 繼續(xù)處理 2xx: 成功——請求已被成功接收、理解、接受 3xx: 重定向——要完成請求必須進(jìn)行更進(jìn)一步的操作 4xx: 客戶端錯誤——請求有語法錯誤或請求無法實現(xiàn) 5xx: 服務(wù)器端錯誤——服務(wù)器未能實現(xiàn)合法請求
報頭
HTTP消息報頭包括普通報頭、請求報頭、響應(yīng)報頭、實體報頭
普通報頭中有少數(shù)報頭域用作所有的請求和響應(yīng)消息, 但并不用作于被傳輸?shù)膶嶓w, 只用于傳輸?shù)南?如緩存控制、連接控制等)請求報頭允許客戶端向服務(wù)端傳遞請求的附加信息以及客戶端自身的信息(如UA頭、Accept等)響應(yīng)報頭允許服務(wù)器傳遞不能放在狀態(tài)行中的附加響應(yīng)信息, 以及關(guān)于服務(wù)器的信息和對 Request-URI 所標(biāo)識的資源進(jìn)行下一步訪問的信息(如Location)。實體報頭定義了關(guān)于實體正文和請求所標(biāo)識的資源的元信息, 例如有無實體正文。比較重要的幾個報頭如下:
Host: 頭域指定請求資源的Internet主機和端口號, 必須表示請求URL的原始服務(wù)器或網(wǎng)關(guān)的位置。HTTP 1.1 請求必須包含主機頭域, 否則系統(tǒng)會以400狀態(tài)碼返回。User-Agent: 簡稱UA, 內(nèi)容包含發(fā)出請求的用戶信息。通常UA包含瀏覽者的信息, 主要是瀏覽器的名詞版本和所用的操作系統(tǒng)。這個UA不僅僅使用瀏覽器才存在, 而是所有使用HTTP協(xié)議的客戶端都會發(fā)送, 這個UA頭是區(qū)分客戶端所使用設(shè)備的重要依據(jù)。Accept: 告訴服務(wù)器可以接受的文件格式。Cookie: Cookie分兩種, 一種是客戶端向服務(wù)器發(fā)送的, 使用Cookie報頭, 用來標(biāo)記一些信息, 另一種是服務(wù)器發(fā)送給瀏覽器的, 報頭為Set-Cookie。二者主要卻別在于Cookie報頭的value可以有多個Cookie值, 并且不需要顯示指定domain等。而Set-Cookie報頭里一條記錄只能有一個Cookie的value, 需要指明domain、path等Cache-Control: 指定請求和響應(yīng)遵循的緩存機制。在請求消息或響應(yīng)消息中設(shè)置Cache0Control并不會修改另一個消息處理過程中的緩存處理機制。請求時的緩存指令包括no-cache、no-store、max-age、max-stale、min-fresh、only-if-cached; 響應(yīng)消息中的指令包括 public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age。Referer: 頭域允許客戶端指定請求URI的資源源地址, 這可以允許服務(wù)器生成回退鏈表, 可以用來登錄、優(yōu)化緩存等。也允許廢除的或錯誤的連接由于維護(hù)的目的被追蹤。Content-Length: 內(nèi)容長度Content-Range: 響應(yīng)的資源范圍。可以在每次請求中標(biāo)記請求的資源范圍, 在連接斷開重連時, 客戶端只請求該資源未下載的部分, 而不是重新請求整個資源, 實現(xiàn)斷點續(xù)傳。Accept-Encoding: 指定所能接受的編碼方式。通常服務(wù)器會對頁面進(jìn)行GZip壓縮后再輸出, 以減少瀏覽, 一般瀏覽器均支持這種壓縮后的數(shù)據(jù)進(jìn)行處理。自定義報頭: 在HTTP消息中, 也可以使用一些Http1.1中未定義的頭字段, 這些字段統(tǒng)稱為自定義的HTTP頭或者擴展頭。php中一系列與HTTP協(xié)議相關(guān)的一系列函數(shù):
array get_headers(string簡單的HTTP協(xié)議使用示例
context 參數(shù)使這些函數(shù)更加靈活, 通過該參數(shù)可以定制HTTP請求, 設(shè)置POST數(shù)據(jù)。
<?php$data = array('author' => 'pchangl', 'mail' => 'pchangl@163.com', 'text' => 'test content.');$data = http_build_query($data);$opts = array( 'http' => array( 'method' => 'POST', 'header' => 'Content-type:application/x-www-form-urlencoded/r/n' . 'Content-Length:' . strlen($data) . "/r/n", 'content' => $data ));$context = stream_context_create($opts);$html = @file_getcontents('http://www.baidu.com/', false, $context);Socket 通常稱為套接字, 用于描述IP地址和端口, 是一個通信鏈的句柄。應(yīng)用程序通過套接字向網(wǎng)絡(luò)發(fā)出請求或者應(yīng)答網(wǎng)絡(luò)請求。Socket既不是一個程序, 也不是一種協(xié)議, 只是操作系統(tǒng)提供的通信層的一組抽象API。
為保證兩個相互通信的進(jìn)程之間即互不干擾又協(xié)調(diào)一致工作, 操作系統(tǒng)為進(jìn)程通信提供了相應(yīng)措施, 如UNIX BSD中的管道(pipe)、命名管道(named pipe)和軟中斷信號(signal), 以及UNIX System V的消息(message)、共享存儲區(qū)(shared memory)和信號量(semaphore)等, 但這些都僅限于在本機進(jìn)程之間的通信。
操作系統(tǒng)支持網(wǎng)絡(luò)協(xié)議眾多, 不同協(xié)議工作方式不同, 地址格式也不同, 因此, 網(wǎng)間通信還要解決多重協(xié)議的識別問題。
為了解決上述問題, TCP/IP協(xié)議引入了下列概念。
端口
網(wǎng)絡(luò)中可以被命名和尋址的通信端口, 是操作系統(tǒng)可分配的一種資源。
端口是一種軟抽象的軟件結(jié)構(gòu)(包括一些數(shù)據(jù)結(jié)構(gòu)和I/O緩沖區(qū))。應(yīng)用程序(即進(jìn)程)通過系統(tǒng)調(diào)用某端口建立連接后, 傳輸層給該端口的數(shù)據(jù)都被相應(yīng)進(jìn)程所接收, 相應(yīng)進(jìn)程發(fā)給傳輸層的數(shù)據(jù)都通過該端口輸出。
TCP和UDP協(xié)議完全是兩個獨立的兩個軟件模塊, 因此各自端口號也相互獨立, TCP有一個255號端口, UDP也有一個255端口號, 二者并不沖突。TCP和UDP都有0~65535個端口號
端口號小于256的定義為常用端口, 服務(wù)器一般通過常用端口號識別客戶端只需要保證該端口號在本機是唯一的。客戶端口號因為存在時間短暫, 又稱臨時端口號大多數(shù)TCP/IP實現(xiàn)給臨時端口號分配1024~5000之間的端口號, 大于5000的端口是給其他服務(wù)預(yù)留的常見的端口有FTP的21號端口, HTTP服務(wù)的80端口, SMTP的25端口和HTTPS的443端口。
地址
網(wǎng)絡(luò)通信中通信的兩個進(jìn)程分別處在不同的機器上。遵循以下原則:
某臺主機可與多個網(wǎng)絡(luò)相連, 必須指定一個網(wǎng)絡(luò)地址網(wǎng)絡(luò)上每臺主機應(yīng)有其唯一地址每臺主機的每個進(jìn)程應(yīng)有在該主機上唯一標(biāo)識符。連接
兩個進(jìn)程間的通信鏈路稱為連接, 連接表現(xiàn)為一些緩沖區(qū)和一組協(xié)議機制。
SOCKET socket(int af, int type, int protocol);
resource socket_create(int $domain, int $type, int $protocol)bool socket_bind(resource $socket, string $address[, int $port = 0])bool socket_listen(resource $socket [, int $backlog = 0])bool socket_set_block(resource $socket)int socket_write(source $socket, string $buffer [, int $length = 0])string socket_read(resource $socket, int $length [, int type = PHP_BINARY_READ])pfsockopen(string $hostname [, int $port = -1 [, int & $errno [, string & $errstr [, float $timeout = ini_get("default_socket_timeout")]]]])bool socket_set_option(resource $socket, int $level, int $optname, mixed $optval)int socket_last_error([resource $socket])建立cURL請求的基本步驟:
初始化設(shè)置選項, 包括URL執(zhí)行并獲取HTML文檔內(nèi)容釋放cURL句柄<?php// 1. 初始化$ch = curl_init();// 2. 設(shè)置選項, 包括URLcurl_setopt($ch, CURLOPT_URL, "http://www.php.net");curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //將curl_exec() 獲取的信息以文件流的形式返回, // 而不是直接輸出curl_setopt($ch, CURLOPT_HEADER, 1); //啟用時會將頭文件的信息作為數(shù)據(jù)流輸出// 3. 執(zhí)行并獲取 HTML 文檔內(nèi)容$output = curl_exec($ch);// 4. 釋放cURL句柄curl_close($ch);echo $output;cURL 常用選項
| 選項 | 描述 |
|---|---|
| CURLOPT_AUTOREFERER | 當(dāng)根據(jù)Location 重定向時, 自動設(shè)置 header 中的 Referer 信息 |
| CURLOPT_COOKIEsession | 啟用時 cURL 會僅僅傳遞一個 Session Cookie, 忽略其他 Cookie, 默認(rèn)情況下 cURL 會將所有 Cookie 返回給服務(wù)器。Session Cookie 指用來判斷服務(wù)端的 Session 是否有效而存在的 Cookie |
| CURLOPT_FOLLOWLOCATION | 啟用將服務(wù)器返回的 Location 放在 Header 中, 遞歸的返回給服務(wù)器, 使用 CURLOPT_MAXREDIRS 可以限定遞歸返回的樹立 |
| CURLOPT_HEADER | 啟用時將頭文件的信息作為數(shù)據(jù)流輸出 |
| CURLOPT_RETURNTRANSFER | 將 curl_exec() 獲取的信息以文件流的形式返回, 而不是直接輸 |
| CURLOPT_INFILESIZE | 設(shè)定上傳文件的大小, 單位為字節(jié)(byte) |
| CURLOPT_MAXCONNECTS | 運行最大連接數(shù)量, 超過會通過CURLOPT_CLOSEPOLICY 決定應(yīng)該停止哪些連接 |
| CURLOPT_MAXREDIRS | 指定 HTTP 重定向的最多數(shù)量, 和 CURLOPT_FOLLOWLOCATION 一起使用 |
| CURLOPT_COOKIE | 設(shè)定 HTTP 請求中 Cookie 部分的內(nèi)容, 多個 Cookie 用分號分隔, 分號后帶一個空格 |
| CURLOPT_COOKIEFILE | 包含 Cookie 數(shù)據(jù)的文件名, Cookie 文件的格式可以是 Netscape 格式, 或者只是純 HTTP 頭部信息存入文件 |
| CURLOPT_ENCODING | HTTP 請求頭中 Accept-Encoding 的值, 支持的編碼有 identity, deflate 和 gzip。如果空字符串”“, 請求頭會發(fā)送所有支持的編碼類型 |
| CURLOPT_POSTFIELDS | 全部數(shù)據(jù)使用 HTTP 協(xié)議中的 POST 操作來發(fā)送。 要發(fā)送文件, 在文件名前面加上@前綴并使用完整路徑。這個參數(shù)通過 urlencoded 后的字符串類似 paral=val1¶2=varl2&… 或使用一個一字段名為鍵, 字段數(shù)據(jù)為值的數(shù)組。如果value是一個數(shù)組, Content-type 頭會被設(shè)置成 multipart/form-data |
| CURLOPT_RANGE | 以 X-Y 的形式組成, 其中 X 和 Y 都是可選項獲取數(shù)據(jù)的范圍, 單位是字節(jié)。 HTTP 傳輸線程也支持幾個這樣的重復(fù)項中間用逗號分隔如 X-Y,N-M |
| CURLOPT_REFERER | HTTP 請求中 Referer 的內(nèi)容 |
| CURLOPT_HTTPHEADER | 用來設(shè)置 HTTP 頭字段的數(shù)組。數(shù)組形式如下: array(‘Content-type: text/plain’, ‘Content-length: 100’) |
| CURLOPT_FILE | 設(shè)置輸出文件的位置, 值是一個資源類型, 默認(rèn)為 STDOUT(瀏覽器) |
| CURLOPT_INFILE | 在上傳文件時需要讀取的文件地址, 值是一個資源類型 |
| CURLOPT_HEADERFUNCTION | 設(shè)置一個回調(diào)函數(shù), 其有兩個參數(shù): 第一個是 cURL 的資源句柄, 第二個是輸出的 hander 數(shù)據(jù)。header 數(shù)據(jù)的輸出必須依賴這個函數(shù), 返回寫入的數(shù)據(jù)大小 |
| CURLOPT_WRITEFUNCTION | 擁有兩個參數(shù)的回調(diào)函數(shù): 第一個參數(shù)是會話句柄, 第二個是 HTTP 響應(yīng)頭信息的字符串。使用此回調(diào)函數(shù), 將自行處理響應(yīng)頭信息。響應(yīng)頭信息是整個字符串。設(shè)置返回值為精確的已寫入字符串長度。發(fā)生錯誤時傳輸線程終止 |
一個輕型的、安全的、跨網(wǎng)際、跨語言的、跨平臺的、跨環(huán)境的、跨域的協(xié)議, 支持復(fù)雜對象傳輸、引用參數(shù)傳遞、內(nèi)容輸出重定向、分級錯誤處理、會話,是面服務(wù)的高性能遠(yuǎn)程過程調(diào)用協(xié)議。
PHPRPC 官網(wǎng): http://phprpc.org/zh_CN/
PHPRPC 作為客戶端
PHPRPC 作為服務(wù)端
PHPRPC 客戶端調(diào)用上面服務(wù)端
Cookie 是在遠(yuǎn)程瀏覽器端存儲數(shù)據(jù)并以此跟蹤和識別用戶的機制。Cookie 是存儲在客戶端上的一小段數(shù)據(jù), 瀏覽器(客戶端) 通過 HTTP 協(xié)議和服務(wù)器進(jìn)行 Cookie 交互。
關(guān)于 Cookie 的 RFC 文檔主要有: RFC 6265、 RFC 2109
Cookie 主要是參照 RFC2019 標(biāo)準(zhǔn)由客戶端實現(xiàn)其生成、使用整個管理過程, 服務(wù)端則參照此標(biāo)準(zhǔn)實現(xiàn)和客戶端之間的交互指令。
Cookie 是 HTTP 頭的一部分, 即先發(fā)送或請求Cookie, 接下來才是data 域,所以setcookie() 等函數(shù)必須在其輸出數(shù)據(jù)之前調(diào)用, 這和 header() 函數(shù)是相同的。也可以使用輸出緩沖函數(shù)延遲腳本的輸出, 直到設(shè)置好所有 Cookie 和其他 HTTP 標(biāo)頭。
正常 Cookie 只能在一個應(yīng)用中共享, 即一個 Cookie 只能由創(chuàng)建它的應(yīng)用獲得。實現(xiàn) Cookie 的跨域, 主要是為了統(tǒng)一應(yīng)用平臺, 即實現(xiàn)目前流行的單點登錄。最簡單的方式就是使用 P3P 協(xié)議。
P3P(Platform for Prvacy Preferences) 協(xié)議由萬維網(wǎng)協(xié)會研制, 為 Web 用戶提供了對自己公開信息的更多控制。
頁面的 Cookie 不能是瀏覽器進(jìn)程的 Cookie, 如不設(shè)置超時時間的 Cookie, 則會跨域會取不到利用 IFRAME 時, 記得要在相應(yīng)的動態(tài)頁面的頁頭添加一下 P3P 的信息, 否則 IE 會把 IFRAME 框里的 Cookie 給阻止掉, 產(chǎn)生問題本身未保存, 自然就去不到了。這其實是 FRAMESET 和 Cookie 的問題, 使用 FRAME 或者 IFRAME 時都會遇到IE 對跨域訪問 Cookie 限制比較嚴(yán)格, 在 Firefox、CHrome 等瀏覽器下測試, 即使不使用 P3P頭信息也能成功如果是多個工程, 其間關(guān)系就變得非常復(fù)雜, 這個時候, 就需要一個完整的 SSO 方案, 通常是通過 SSO Server 系統(tǒng)進(jìn)行中轉(zhuǎn), CAS 就是一個成熟的 SSO 解決方案。而不是使用跨域 Cookie。
一個域名的每個 Cookie 限制在4千字節(jié)鍵值對的形式存在, 如果要在本地存儲數(shù)據(jù), 可以使用localStorage本地存儲。
//檢測瀏覽器是否支持 localStorageif (window.localStorage) { alert('This browser supports localStorage');} else { alert('This browser does not support localStorage');}HTML 5 本地存儲只能存儲字符串, 任何格式存儲的時候都會被自動轉(zhuǎn)化為字符串, 所以讀取的時候, 需要自己進(jìn)行類型轉(zhuǎn)換。
HTML 5 監(jiān)聽 storage 鍵值對改變事件:
if (window.AddEventListener) { window.addEventListener("storage", handle_storage, false);} else if(window.attachEvent) { window.attachEvent("onstorage", handle_storage);}function handle_storage(e){ if (!e) { e = window.event; } // showStorage();}Session 即會話, 指一種持續(xù)性的、雙向的連接。Session 和 Cookie 本質(zhì)上沒什么區(qū)別, 都是針對 HTTP 協(xié)議局限性而提出的一種保持客戶端和服務(wù)器之間保持會話狀態(tài)的機制。
Session 指用戶在瀏覽某個網(wǎng)站時, 從進(jìn)入網(wǎng)站到瀏覽器關(guān)閉這段時間內(nèi)的會話。
要使用 Session 必須在程序的最開始處執(zhí)行 session_start(), 前面不能有任何輸出內(nèi)容, 否則就會拋出 WARNING 級別錯誤。
Session 通過一個稱為 PHPSESSID 的 Cookie 和服務(wù)器聯(lián)系。Session 是通過 SessionID 判斷客戶端用戶的, 即 Session 文件的文件名。
Session 的回收是被動的, 為了保證過期的 Session 能被正常回收, 可以修改 PHP配置文件中的 session.gc_divisor 參數(shù)提高回收率(太大了會增加負(fù)載), 或者設(shè)置一個變量判斷是否過期。
訪問量大的網(wǎng)站可以通過使用 session_set_save_handler函數(shù)來將 session 存儲在 Data Base(數(shù)據(jù)庫、內(nèi)存表、APC等)中。
新聞熱點
疑難解答