HTTP Get,Post請求詳解

輕舟輕發表於2016-12-20

轉載:http://blog.chinaunix.net/uid-25808509-id-3047968.html

請求型別
三種最常見的請求型別是:GET,POST 和 HEAD

GET:獲取一個文件
大部分被傳輸到瀏覽器的html,images,js,css, … 都是通過GET方法發出請求的。它是獲取資料的主要方法。

例如,要獲取Nettuts+ 的文章,http request的第一行通常看起來是這樣的:

GET /tutorials/other/top-20-mysql-best-practices/ HTTP/1.1

一旦html載入完成,瀏覽器將會傳送GET 請求去獲取圖片,就像下面這樣:

GET /wp-content/themes/tuts_theme/images/header_bg_tall.png HTTP/1.1

表單也可以通過GET方法傳送,下面是個例子:


First Name:
Last Name:

當這個表單被提交時,HTTP request 就會像這樣:

GET /foo.php?first_name=John&last_name=Doe&action=Submit HTTP/1.1
...

你可以將表單輸入通過附加進查詢字串的方式傳送至伺服器。


POST:傳送資料至伺服器
儘管你可以通過GET方法將資料附加到url中傳送給伺服器,但在很多情況下使用POST傳送資料給伺服器更加合適。通過GET傳送大量資料是不現實的,它有一定的侷限性。

用POST請求來傳送表單資料是普遍的做法。我們來吧上面的例子改造成使用POST方式:


First Name:
Last Name:

提交這個表單會建立一個如下的HTTP 請求:

POST /foo.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://localhost/test.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 43
first_name=John&last_name=Doe&action=Submit

這裡有三個需要注意的地方:

第一行的路徑已經變為簡單的 /foo.php , 已經沒了查詢字串。
新增了 Content-Type 和 Content-Lenght 頭部,它提供了傳送資訊的相關資訊。所有資料都在headers之後,以查詢字串的形式被髮送.
POST方式的請求也可用在AJAX,應用程式,cURL … 之上。並且所有的檔案上傳表單都被要求使用POST方式。

HEAD:接收頭部資訊
HEAD和GET很相似,只不過HEAD不接受HTTP響應的內容部分。當你傳送了一個HEAD請求,那就意味著你只對HTTP頭部感興趣,而不是文件本身。

這個方法可以讓瀏覽器判斷頁面是否被修改過,從而控制快取。也可判斷所請求的文件是否存在。

例如,假如你要訪問的網站上有很多連結,那麼你就可以簡單的給他們分別傳送HEAD請求來判斷是否存在死鏈,這比使用GET要快很多。

HTTP Headers 中的 HTTP請求
現在我們來看一些在HTTP headers中常見的HTTP請求資訊。

所有這些頭部資訊都可以在PHP的$_SERVER陣列中找到。你也可以用getallheaders() 函式一次性獲取所有的頭部資訊。

Host
一個HTTP請求會傳送至一個特定的IP地址,但是大部分伺服器都有在同一IP地址下託管多個網站的能力,那麼伺服器必須知道瀏覽器請求的是哪個域名下的資源。

Host: rlog.cn

這只是基本的主機名,包含域名和子級域名。

在PHP中,可以通過$_SERVER['HTTP_HOST'] 或 $_SERVER['SERVER_NAME']來檢視。

User-Agent
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)

這個頭部可以攜帶如下幾條資訊:

瀏覽器名和版本號.
作業系統名和版本號.
預設語言.
這就是某些網站用來收集訪客資訊的一般手段。例如,你可以判斷訪客是否在使用手機訪問你的網站,然後決定是否將他們引導至一個在低解析度下表現良好的移動網站。

在PHP中,可以通過 $_SERVER['HTTP_USER_AGENT'] 來獲取User-Agent

if ( strstr($_SERVER['HTTP_USER_AGENT'],'MSIE 6') ) {
echo "Please stop using IE6!";
}


Accept-Language
Accept-Language: en-us,en;q=0.5

這個資訊可以說明使用者的預設語言設定。如果網站有不同的語言版本,那麼就可以通過這個資訊來重定向使用者的瀏覽器。

它可以通過逗號分割來攜帶多國語言。第一個會是首選的語言,其它語言會攜帶一個“q”值,來表示使用者對該語言的喜好程度(0~1)。

在PHP中用 $_SERVER["HTTP_ACCEPT_LANGUAGE"] 來獲取這一資訊。

if (substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2) == 'fr') {
header('Location: http://french.mydomain.com');
}


Accept-Encoding
Accept-Encoding: gzip,deflate

大部分的現代瀏覽器都支援gzip壓縮,並會把這一資訊報告給伺服器。這時伺服器就會壓縮過的HTML傳送給瀏覽器。這可以減少近80%的檔案大小,以節省下載時間和頻寬。

在PHP中可以使用 $_SERVER["HTTP_ACCEPT_ENCODING"] 獲取該資訊。 然後呼叫ob_gzhandler()方法時會自動檢測該值,所以你無需手動檢測。

// enables output buffering
// and all output is compressed if the browser supports it
ob_start('ob_gzhandler');

If-Modified-Since
如果一個頁面已經在你的瀏覽器中被快取,那麼你下次瀏覽時瀏覽器將會檢測文件是否被修改過,那麼它就會傳送這樣的頭部:

If-Modified-Since: Sat, 28 Nov 2009 06:38:19 GMT

如果自從這個時間以來未被修改過,那麼伺服器將會返回“304 Not Modified”,而且不會再返回內容。瀏覽器將自動去快取中讀取內容

在PHP中,可以用$_SERVER['HTTP_IF_MODIFIED_SINCE'] 來檢測。

// assume $last_modify_time was the last the output was updated
// did the browser send If-Modified-Since header?
if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
// if the browser cache matches the modify time
if ($last_modify_time == strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
// send a 304 header, and no content
header("HTTP/1.1 304 Not Modified");
exit;
}
}

還有一個叫Etag的HTTP頭資訊,它被用來確定快取的資訊是否正確,稍後我們將會解釋它。

Cookie
顧名思義,他會傳送你瀏覽器中儲存的Cookie資訊給伺服器。

Cookie: PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120; foo=bar

它是用分號分割的一組名值對。Cookie也可以包含session id。

在PHP中,單一的Cookie可以訪問$_COOKIE陣列獲得。你可以直接用$_SESSION array獲取session變數。如果你需要session id,那麼你可以使用session_id()函式代替cookie。

echo $_COOKIE['foo'];
// output: bar
echo $_COOKIE['PHPSESSID'];
// output: r2t5uvjq435r4q7ib3vtdjq120
session_start();
echo session_id();
// output: r2t5uvjq435r4q7ib3vtdjq120


Referer
顧名思義, 頭部將會包含referring url資訊。

例如,我訪問Nettuts+的主頁並點選了一個連結,這個頭部資訊將會傳送到瀏覽器:
Referer: http://net.tutsplus.com/

在PHP中,可以通過 $_SERVER['HTTP_REFERER'] 獲取該值。

if (isset($_SERVER['HTTP_REFERER'])) {
$url_info = parse_url($_SERVER['HTTP_REFERER']);
// is the surfer coming from Google?
if ($url_info['host'] == 'www.google.com') {
parse_str($url_info['query'], $vars);
echo "You searched on Google for this keyword: ". $vars['q'];
}
}
// if the referring url was:
// http://www.google.com/search?source=ig&hl=en&rlz=&=&q=http+headers&aq=f&oq=&aqi=g-p1g9
// the output will be:
// You searched on Google for this keyword: http headers

You may have noticed the word “referrer” is misspelled as “referer”. Unfortunately it made into the official HTTP specifications like that and got stuck.


HTTP Headers 中的 HTTP響應
現在讓我瞭解一些常見的HTTP Headers中的HTTP響應資訊。

在PHP中,你可以通過 header() 來設定頭部響應資訊。PHP已經自動傳送了一些必要的頭部資訊,如 載入的內容,設定 cookies 等等… 你可以通過 headers_list() 函式看到已傳送和將要傳送的頭部資訊。你也可以使用headers_sent()函式來檢查頭部資訊是否已經被髮送。

Cache-Control
w3.org 的定義是:“The Cache-Control general-header field is used to specify directives which MUST be obeyed by all caching mechanisms along the request/response chain.” 其中“caching mechanisms” 包含一些你ISP可能會用到的 閘道器和代理資訊。

例如:

Cache-Control: max-age=3600, public

“public”意味著這個響應可以被任何人快取,“max-age” 則表明了該快取有效的秒數。允許你的網站被快取降大大減少下載時間和頻寬,同時也提高的瀏覽器的載入速度。

也可以通過設定 “no-cache” 指令來禁止快取:

Cache-Control: no-cache

更多詳情請參見w3.org。

Content-Type
這個頭部包含了文件的”mime-type”。瀏覽器將會依據該引數決定如何對文件進行解析。例如,一個html頁面(或者有html輸出的php頁面)將會返回這樣的東西:

Content-Type: text/html; charset=UTF-8

‘text’ 是文件型別,‘html’則是文件子型別。 這個頭部還包括了更多資訊,例如 charset。

如果是一個圖片,將會傳送這樣的響應:

Content-Type: image/gif

瀏覽器可以通過mime-type來決定使用外部程式還是自身擴充套件來開啟該文件。如下的例子降呼叫Adobe Reader:

Content-Type: application/pdf

直接載入,Apache通常會自動判斷文件的mime-type並且新增合適的資訊到頭部去。並且大部分瀏覽器都有一定程度的容錯,在頭部未提供或者錯誤提供該資訊的情況下它會去自動檢測mime-type。

你可以在這裡找到一個常用mime-type列表。

在PHP中你可以通過 finfo_file() 來檢測檔案的ime-type。


Content-Disposition
這個頭部資訊將告訴瀏覽器開啟一個檔案下載視窗,而不是試圖解析該響應的內容。例如:

Content-Disposition: attachment; filename="download.zip"

他會導致瀏覽器出現對話方塊。
注意,適合它的Content-Type頭資訊同時也會被髮送

Content-Type: application/zip
Content-Disposition: attachment; filename="download.zip"

Content-Length
當內容將要被傳輸到瀏覽器時,伺服器可以通過該頭部告知瀏覽器將要傳送檔案的大小(bytes)。

Content-Length: 89123

對於檔案下載來說這個資訊相當的有用。這就是為什麼瀏覽器知道下載進度的原因。

例如,這裡我寫了一段虛擬指令碼,來模擬一個慢速下載。

// it's a zip file
header('Content-Type: application/zip');
// 1 million bytes (about 1megabyte)
header('Content-Length: 1000000');
// load a download dialogue, and save it as download.zip
header('Content-Disposition: attachment; filename="download.zip"');
// 1000 times 1000 bytes of data
for ($i = 0; $i < 1000; $i++) {
echo str_repeat(".",1000);
// sleep to slow down the download
usleep(50000);
}


現在,我將Content-Length頭部註釋掉:

// it's a zip file
header('Content-Type: application/zip');
// the browser won't know the size
// header('Content-Length: 1000000');
// load a download dialogue, and save it as download.zip
header('Content-Disposition: attachment; filename="download.zip"');
// 1000 times 1000 bytes of data
for ($i = 0; $i < 1000; $i++) {
echo str_repeat(".",1000);
// sleep to slow down the download
usleep(50000);
}


Etag
這是另一個為快取而產生的頭部資訊。它看起來會是這樣:

Etag: "pub1259380237;gz"

伺服器可能會將該資訊和每個被髮送檔案一起響應給瀏覽器。該值可以包含文件的最後修改日期,檔案大小或者檔案校驗和。瀏覽會把它和所接收到的文件一起快取。下一次當瀏覽器再次請求同一檔案時將會傳送如下的HTTP請求:

If-None-Match: "pub1259380237;gz"

如果所請求的文件Etag值和它一致,伺服器將會傳送304狀態碼,而不是2oo。並且不返回內容。瀏覽器此時就會從快取載入該檔案。


Last-Modified
顧名思義,這個頭部資訊用GMT格式表明了文件的最後修改時間:

Last-Modified: Sat, 28 Nov 2009 03:50:37 GMT

$modify_time = filemtime($file);
header("Last-Modified: " . gmdate("D, d M Y H:i:s", $modify_time) . " GMT");

它提供了另一種快取機制。瀏覽器可能會傳送這樣的請求:

If-Modified-Since: Sat, 28 Nov 2009 06:38:19 GMT

在If-Modified-Since一節我們已經討論過了。

Location
這個頭部是用來重定向的。如果響應程式碼為 301 或者 302 ,伺服器就必須傳送該頭部。例如,當你訪問 http://www.nettuts.com 時瀏覽器就會收到如下的響應:

HTTP/1.x 301 Moved Permanently
...
Location: http://net.tutsplus.com/
...

在PHP中你可以通過這種方式對訪客重定向:
header('Location: http://net.tutsplus.com/');

預設會傳送302狀態碼,如果你想傳送301,就這樣寫:

header('Location: http://net.tutsplus.com/', true, 301);


當一個網站需要設定或者更新你瀏覽的cookie資訊時,它就會使用這樣的頭部:

Set-Cookie: skin=noskin; path=/; domain=.amazon.com; expires=Sun, 29-Nov-2009 21:42:28 GMT
Set-Cookie: session-id=120-7333518-8165026; path=/; domain=.amazon.com; expires=Sat Feb 27 08:00:00 2010 GMT

每個cookie會作為單獨的一條頭部資訊。注意,通過js設定cookie將不會體現在HTTP頭中。

在PHP中,你可以通過setcookie()函式來設定cookie,PHP會傳送合適的HTTP 頭。

setcookie("TestCookie", "foobar");

它會傳送這樣的頭資訊:

Set-Cookie: TestCookie=foobar

如果未指定到期時間,cookie就會在瀏覽器關閉後被刪除。

WWW-Authenticate
一個網站可能會通過HTTP傳送這個頭部資訊來驗證使用者。當瀏覽器看到頭部有這個響應時就會開啟一個彈出窗。

WWW-Authenticate: Basic realm="Restricted Area"

Content-Encoding
這個頭部通常會在返回內容被壓縮時設定。

Content-Encoding: gzip


相關文章