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