http://unifreak.github.io/translation/Http_headers_and_PHP_header()_function
引言
許多初級到中級的的 PHP 程序員把 header() 函數當作某種神秘巫術. 他們可以照着代碼示例把功能實現, 但是還是不知道到底它是如果運作的. 我最開始就是這樣的.
實際上它非常簡單. 在這篇文章中, 我會解釋 HTTP 頭(header) 是如何運作的, 它們與 PHP 的關系, 以及它們的 meta 標簽 equivalents(對應物)
希望你讀完之后, 能更順手的使用 header() 函數, 甚至想出一些更多利用它的地方. 我們也會講到其他一些關於 HTTP 和 PHP 的重要話題. 但是在我們開始講任何程序相關的東西之前, 我們需要先快速(並且不完整的)過一遍 HTTP (HyperTex Transfer Protocol) 運作原理
HTTP 概覽
Headers: 對話中的詞語
HTTP 是 web 服務器和客戶端瀏覽器之間的數據傳輸(比如 web 頁面中的 HTML, 圖片, 文件)協議(‘規則’集合), 並且通常使用 80 端口. 這就是網站 URL 前面 ‘http://
’ 的來源
很多人最開始制作 web 頁面的時候, 他們先在本地電腦上寫 HTML, 在本地瀏覽器查看是否符合預期, 然后上傳到服務器, 就可以在網上瀏覽這些頁面了. 看起來好像在無論在本地查看與在服務器上查看的頁面都一樣, 傳輸的數據只有這些 HTML 以及它包含的圖片. 但是實際上還有另外一些許多你沒看到的信息 - 頭信息.
頭信息可以分為兩大類: 你瀏覽器向服務器請求文件時發出的請求頭信息, 服務器提供文件給瀏覽器時發出的響應頭信息. 把這些頭信息當作瀏覽器和服務器對話時的詞語. 我喜歡把服務器想象為圖書管理員, 把瀏覽器想象成正在請求圖書資源的學者. 瀏覽器走向位於服務台 (80 端口) 的服務器, 說道, “Hi, 我是 Mozilla, 我正在找這個編目號是 ‘www.expertsrt.com’ 的資源. 你可以幫我找到它嗎?” 服務器聽到后回應 “是的, 我找到了, 讓我把它給你. 這里面是 HTML 文本, 它寫的是 ‘<html>...
’” 瀏覽器開始從頭到尾的讀它, 並且遇到了一個圖片標簽, 所以向服務器要位於 src 屬性指定處的圖片. 服務器進行查找, 找到這個文件然后說道 “這是個 PNG 圖片, 它的數據是…” 你懂的.
另一個對話可能像這樣:
瀏覽器: Hi, 我是 Mozilla, 能給我在 ‘www.expertsrt.com/moved.html’ 這里的文件嗎?.
服務器: 那個文件已經不在那兒了, 他現在在 ‘www.expertsrt.com/newloc.html’.
瀏覽器: Hi, 我是 Mozilla, 能給我在 ‘www.expertsrt.com/newloc.html’ 這里的文件嗎?
服務器: 我找到這個文件了. 查看它 10 秒鍾然后再向我問一次. 它是一個 HTML 文本文件, 它有這些內容…
…10 秒鍾…
瀏覽器: Hi, 我是 Mozilla, 能給我在 ‘www.expertsrt.com/newloc.html’ 這里的文件嗎?
服務器: 我找到這個文件了. 查看它 10 秒鍾然后再向我問一次. 它是一個 HTML 文本文件, 它有這些內容…
…10 秒鍾…
瀏覽器: Hi, 我是 Mozilla, 能給我在 ‘www.expertsrt.com/newloc.html’ 這里的文件嗎?
服務器: 我找到這個文件了. 查看它 10 秒鍾然后再向我問一次. 它一個 HTML 文本文件, 它有這些內容…
…諸如這般, 直到瀏覽器被用戶重新定向…
正如你所看到的, 使用頭信息可以控制許多事情. 使用 header() 函數, 你可以讓服務器發送你所需的頭信息, 這樣你可以做除了發送 HTML 之外許多很酷的事情.
看看整個對話過程
在繼續之前, 讓我們先不使用瀏覽器來查看一個 web 頁面, 這樣我們可以看到整個對話, 更好的了解 HTTP 頭的工作. 先打開命令行 (在 windows 中, 點擊開始菜單->運行, 輸入 cmd
, 然后點擊 “OK”…如果你正使用 linux, 你或許已經知道怎么打開了). 在命令行中輸入:
telnet expertsrt.com 80
然后回車. 這會鏈接到 expersrt.com 的 80 端口. 然后, 復制並粘貼下面的文字:
GET / HTTP/1.1
Host: expertsrt.com
如果你輸入或粘貼這些文字的時候, 命令行除了光標的閃爍沒看到任何動靜的話, 不要擔心 – 它們確實被發送到服務器了. 第一行說明你使用 GET 請求方法去獲取資源 / (這里是目標主機上基目錄里的文件), 並且你在使用 HTTP 1.1 版本. 第二行告訴服務器你想要連接到哪台主機. 當你輸入 ‘expertsrt.com’ 后, 回車兩次 (只需兩次). 你應當立刻得到類似下面的響應:
HTTP/1.1 301 Moved Permanently
Date: Wed, 08 Feb 2006 07:44:07 GMT
Server: Apache/2.0.54 (Debian GNU/Linux) mod_auth_pgsql/2.0.2b1 mod_ssl/2.0.54 OpenSSL/0.9.7e
Location: http://www.expertsrt.com/
Content-Length: 233
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>301 Moved Permanently</title> </head><body> <h1>Moved Permanently</h1> <p>The document has moved <a href="http://www.expertsrt.com/">here</a>.</p> </body></html>
哎呀! 看起來好像我們請求的文件已經不在那兒了; 它已經被移到新的地方了: http://www.expertsrt.com
. 如果你使用瀏覽器, 你只會看到 HTML - 在第一個空白行之前的都是頭信息. 實際上, 現代瀏覽器比這更智能 - 當他們看到第三行的新的 URL 時, 會自動轉向那里, 這樣你就不用手動再輸入這個新的 URL 了. 讓我們去這個新的 URL. 這時可能你已經斷開連接了. 如果這樣, 只需按向上鍵, telnet 命令會出現, 然后回車以重新連接. 如果你沒有斷開連接, 那直接輸入下面的文字就行:
GET / HTTP/1.1
Host: www.expertsrt.com
然后回車兩次. 你會看到另一個類似的響應, 告訴你那個頁面實際上在 http://www.expertsrt.com/index.php
. 服務器真挑剔是不是? ;-) 重復上面的操作, 不過這次輸入
GET /index.php HTTP/1.1
Host: www.expertsrt.com
注意我們想要的文件名在第一行. 這一次我們屏幕被文字刷滿了: 這就是來自 ERT 主頁的 HTML. 這里的頭信息看起來是這樣的
HTTP/1.1 200 OK
Date: Wed, 08 Feb 2006 08:20:07 GMT
Server: Apache/2.0.54 (Debian GNU/Linux) mod_auth_pgsql/2.0.2b1 mod_ssl/2.0.54 OpenSSL/0.9.7e
X-Powered-By: PHP/4.4.0
Transfer-Encoding: chunked
Content-Type: text/html
很簡單是不是? 我們來繼續探討這跟你編程有什么關系. 如果你不明白我們講到的所有事情也沒有關系. 重要的是對瀏覽器和服務器如何交互的有個大致印象, 以及意識到並沒有什么魔法在里面. 最終就是這些
- 瀏覽器和服務器通過使用頭信息來進行交互
- 頭信息在主要內容之前發送, 並且用兩個 CRLF/換行符 來和主要內容分割開
-
在頭信息部分, 每一行就是一個頭. 首先是頭的名字, 然后是一個冒號一個空格, 然后是這個頭的名/值
頭名: 頭值
- 頭信息可以包括許多類型的信息和指示, 以便瀏覽器和服務器用來告知對方接下來該做什么
提示: 如果你是那種刨根問底的人, 你可以看看 RFC 2616, 那是 HTTP/1.1 的完整規范. 尤其是 14 章, 包含每一個頭的完整定義
PHP header(): 基礎
注意在我們最終得到的主頁中的 X-Powered-By: PHP/4.4.0 和 Content-Type: text/html 這兩個頭信息. PHP 一開始就被設計成輸出 HTML ( PHP 中的 H 即代表 ‘Hypertext’), 並且在 PHP 腳本第一次生成輸出(比如, 使用 echo)時, 會自動為你包含這些頭信息. 這非常方便, 但也造成許多 PHP 新手對頭信息的困惑 - 在像 Perl 這樣不是一開始就被設計成用於 web 開發的語言中, 不包含你自己的頭而直接發送輸出會產生 ‘500 Internal Server Error’ 錯誤, 所以 Perl 的 web 開發者不得不立即學習關於頭信息的知識
header()
函數發送 HTTP 響應頭信息, 而且只做這件事
使用這個函數, 你可以讓你的腳本發送你選擇的頭信息給瀏覽器, 創造一個非常有用的動態結果. 但是, 你需要知道關於 header()
函數的第一件事就是你必須在 PHP 發送任何輸出(這會使 PHP 自動發送默認的頭信息)之前使用它
我懷疑有哪個 PHP 程序員沒有見到過如下的錯誤消息
Warning: Cannot modify header information - headers already sent by.....
如我們所說的, 響應頭信息用一個空白行和主要內容分割. 這意味你僅可以發送頭信息一次, 如果你的腳本有任何輸出 (即使一個在 <?php
標簽之前的空白行或空格), PHP 就會自動發送頭信息. 例如, 看一下下面這個腳本, 看起來邏輯上很正常:
Welcome to my website!<br /> <?php if($test){ echo "You're in!"; } else{ header('Location: http://www.mysite.com/someotherpage.php'); } ?>
這個腳本判斷 $test
是否為 true, 如果不是則使用 Location
頭重定向訪問者. 看到問題所在了嗎? ‘Welcome…’ 文字始終會發送出去, 所以默認的頭信息會自動被發送. 在調用 header()
時已經太晚了: 用戶只看到一條錯誤消息 (如果你把錯誤報告關掉了, 則只會看到 ‘Welcome…’ 文字), 而不是被重定向
基本上有兩種解決方法. 第一個就是重寫代碼
<?php if($test){ echo 'Welcome to my website<br />You're in!'; } else{ header('Location: http://www.mysite.com/someotherpage.php'); } ?>
第二個就是使用輸出緩沖, 這個解決方法更為優雅易用. 在我們上面的例子中, 重寫代碼並不困難, 但是試想一下如果有很多 HTML 需要移動位置 - 這樣做就會很麻煩, 也會讓我們的代碼更難追蹤. 雖然我們第一個示例導致了錯誤, 但是邏輯上是沒錯的. 輸出緩沖可以讓你一直保留(‘緩沖’)輸出(即使是 PHP 代碼之外的 HTML)直到你明確指示了把輸出發送給瀏覽器. 這樣你就可以隨意編寫你的代碼, 知道你指定了你需要指定的頭信息, 然后明確指示發送這些輸出. 兩個相關的函數是 ob_start()
和 ob_flush()
, ob_start()
用於打開輸出緩沖, ob_flush()
會發送緩沖了的輸出:
<?php ob_start(); //開始輸出緩沖 ?> Welcome to my website! <?php if(true){ echo "You're in!"; } else{ header('Location: http://www.mysite.com/someotherpage.php'); } ob_flush(); //輸出緩沖中的數據 ?>
我鼓勵你讀一下所有關於輸出緩沖的函數, 非常有用. 你應當盡早的把輸出緩沖發送出去, 尤其當你有許多東西想要發送的時候. 否則你的頁面會看起來加載的很慢, 因為所有的內容只有被組裝完畢后才發送, 而不是當可用的時候立即就被發送出去.
提示: 第二個參數 如果你調用 header() 不止一次發送同一個頭, 這個頭的值將會是_最后_調用的 header() 中設置的值. 如,
<?php header('Some-Header: Value-1'); header('Some-Header: Value-2'); ?>
會產生 Some-Header: Value-2
這個結果. 你可以通過設置第二個參數來發送同一個頭兩次. 這個參數默認是 true. 如果你設置其為 false, 那么第二個頭值不會替換第一個, 而是兩個都被發送. 所以下面的代碼
<?php header('Some-Header: Value-1'); header('Some-Header: Value-2', false); //不要替換第一個 ?>
將會產生 Some-Header: Value-1, Value-2
這個結果. 你很少會用到這個, 但是知道它也不錯.
知道了 HTTP header 和 PHP 如何配合之后, 讓我們來看一些更為具體的例子.
PHP header(): 一些例子
提示: 下面這個代碼片斷都是截取自完整的工作代碼. 當你在自己的程序中包含他們的時候, 記得定義所有你自己的變量, 賦給他們默認值, 以及遵循其他最佳實踐.
使用 Location
頭重定向
我們已經在上面看到過幾次了: 它會重定向瀏覽器.
<?php header('Location: http/www.mysite.com/new_location.html'); ?>
雖然你給它一個相對 URL 沒准也能工作, 但是根據 HTTP 規范, 你真的應該使用一個絕對 URL.
一個容易犯的錯誤就是在使用了 Location header 之后不立即使用 exit
以結束執行 (你可能不是總是想要結束執行, 但是大部分時間是的). 之所以這是一個錯誤是因為 PHP 代碼會繼續執行, 即使用戶已經被重定向到新的 URL. 在最好的情況下, 這會不必要的使用系統資源. 在最壞的情況下, 你可能會執行一些讓自己后悔的操作. 看一下下面的代碼:
<?php //重定向訪問級別低於 4 的用戶 if (check_access_level($username) < 4){ header('Location: http://www.mysite.com/someotherpage.php'); } //向高於訪問級別 4 的用戶發送秘密郵件 mail_secret_code($username); echo 'The secret email is on its way!'; ?>
未授權用戶的確被重定向了, 但是因為代碼會繼續執行, 他們同樣會收到郵件. 為了避免這種情況, 針對已授權用戶的代碼可以寫到 else{}
聲明中, 但是直接在 header()
后面使用 exit
來結束代碼執行會更為干凈容易一些.
<?php //重定向訪問級別低於 4 的用戶 if (check_access_level($username) < 4){ header('Location: http://www.mysite.com/someotherpage.php'); exit; //停止代碼執行 } //向高於訪問級別 4 的用戶發送秘密郵件 mail_secret_code($username); echo 'The secret email is on its way!'; ?>
使用 Refresh
頭重定向
Refresh
和 Location
一樣可以重定向用戶, 但是你可以延遲重定向. 例如, 下面的代碼會在顯示當前頁面 10 秒鍾后重定向用戶到新的頁面:
<?php header('Refresh: 10; url=http://www.mysite.com/otherpage.php'); echo 'You will be redirected in 10 seconds'; ?>
另一個常見的用途就是通過重復的’重定向’一個頁面到它自身來強制更新頁面 (參見上面的第二個 ‘對話’). 例如, 這里是一個簡單的例子, 頁面會從 10 開始向下數, 每個數字之間有 3 秒間隔:
<?php if(!isset($_GET['n'])){ $_GET['n'] = 10; } if($_GET['n'] > 0){ header('Refresh: 3; url=' . $_SERVER['PHP_SELF'].'?n=' . ($_GET['n']-1) ); echo $_GET['n']; } else{ echo 'BLAST OFF!'; } ?>
提示: 如果刷新時間設置成 0, 則 Refresh
頭實際上和 Location
頭完全一樣
使用 Content-Type
頭來提供不同類型的文件以及生成動態內容
服務器用 Content-Type
頭告訴瀏覽器自己將要發送什么類型的數據. 使用這個頭信息, 你可以讓 PHP 腳本輸出任何類型的文件, 從純文本文件到圖片文件到 zip 文件等等. 下面的表格列舉了最常用的一個 MIME 類型:
常用 MIME 類型:
類型 | 描述 |
---|---|
text/html | HTML (PHP 默認) |
text/plain | 純文本 |
image/gif | GIF 圖片 |
image/jpeg | JPEG 圖片 |
image/png | PNG 圖片 |
video/mpeg | MPEG 視頻 |
audio/wav | WAV 音頻 |
audio/mpeg | MP3 音頻 |
video/mov | mov 視頻 |
video/quicktime | Quicktime 視頻 |
video/x-ms-wmv | Windows WMV 視頻 |
audio/x-ms-wma | Windows WMA 音頻 |
audio/x-realaudio | RealPlayer 音頻/視頻 (.rm) |
audio/x-pn-realaudio | RealPlayer 音頻/視頻 (.ram) |
video/x-msvideo | ms 視頻 |
video/avi | AVI 視頻 |
application/pdf | PDF 文檔 |
application/msword | MS Word .doc 文件 |
application/zip | Zip 文件 |
application/octet-stream | 其他. 數據. 用於強制下載或使用應用打開.* |
x-foo/x-bar | 其他. 數據. 用於強制下載或使用應用打開.* |
你可以用此來做一些有趣的事情. 比如, 你可能想要向用戶發用一個預先格式化過的文本文件, 而不是 HTML:
<?php header('Content-Type: text/plain'); echo $plain_text_content; ?>
另或者你想要提示用戶下載文件, 而不是在瀏覽器中查看它. 使用 Content-Disposition
頭, 這很容易, 你甚至可以推薦一個文件名給用戶:
<?php header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; ' .'filename="plain_text_file.txt"'); echo $plain_text_content; ?>
另或者你需要提供文件文件, 但是又希望隱藏文件的真實路徑和名字, 並且只讓已登錄的用戶下載:
<?php if($b_is_logged_in){ header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; ' .'filename="'.$different_filename.'"'); readfile('/path/to/files/' . $filename); } else{ echo 'You are not authorized to view this file'; } ?>
又或者你已經使用 PHP 的圖片函數動態生成了一個圖片, 想要展示給用戶. 你可以創建一個 build_image.php
文件, 像這樣
<?php //生成圖片, 然后 header('Content-Type: image/jpeg'); imagejpeg($image_resouce); ?>
提示: 當心 magic_quotes
! PHP 會自動使用反斜杠轉移特殊字符, 這一開始看起來是個好主意, 但是大多數好的程序員認為 (a) 這會鼓勵不去驗證輸入的粗心代碼, 並且 (b) 在良好的代碼中會產生本不該有 (如果 magic_quote
關閉) 的麻煩. 其中一個麻煩就是二進制數據被破壞. 在上面這個例子中, 如果 magic_quotes_runtime
被啟用, 則 readfile()
輸出的數據可能被添加反斜杠, 導致發送給用戶的文件被破壞. 完美情況下, 你應該在 php.ini
文件中關閉 magic_quotes_runtime
選項, 但是如果你沒有權限訪問這個配置文件, 你可以使用 set_magic_quotes_runtime()
函數 (給它傳個數字 0) 關閉它.
令人高興的是, 最近的一次 PHP 開發者會議顯示, 在未來版本(6+) 的 PHP 中 magic quotes
會被棄用. 但是在所有人升級到這個版本的 PHP 之前, 記住這個導致的問題會節省你很多麻煩和疑問.
你可以在 URL 中傳遞生成圖片所需的參數, 然后使用 $_GET 獲取它們. 然后在另一個頁面, 你可以使用 img 標簽來包含這個圖片:
<img src="build_image.php<?php echo "?$user_id&$caption"; ?>">
可用的地方幾乎講不完. 你 PHP 變成越多, 越會發現 Content-Type
頭真的是你的好朋友
提示: 瀏覽器處理各式 MIME類型
的_預期_方式以及_實際_方式可能並不一致 (尤其是 Internet Explorer), 所以你最好是在你需要支持的瀏覽器中測試一下. PHP 參考中的用戶評論有許多關於此的技巧.
防止頁面緩存
PHP 頁面通常會生成非常動態的內容, 為了防止用戶因為頁面緩存而錯過了更新過的頁面, 告訴瀏覽器不要緩存特定的頁面通常非常有用. 下面的代碼在可能會訪問你網站的瀏覽器中工作的很好:
<?php header('Cache-Control: no-cache, no-store, must-revalidate'); //HTTP/1.1 header('Expires: Sun, 01 Jul 2005 00:00:00 GMT'); header('Pragma: no-cache'); //HTTP/1.0 ?>
Expires
頭可以是任何已經過去的日期. 對於 MIME 類型
, 瀏覽器 (尤其是較老的) 可能不會總是正確的理解你的緩存指示 (雖然大部分現代瀏覽器會).
其他應用
還有另外一個可以使用頭信息的地方, 比如設置 HTTP 響應碼, 或者執行 HTTP 認證 (如果你作為 Apache
模塊來使用 PHP 的話). 現在, 你了解了 header() 如何工作及怎么使用它, 你可以用它做你之前想都沒想到的許多事情了.
PHP 中的請求頭信息
我們講了怎么使用響應頭信息了. 我們還可以從瀏覽器發給服務器的請求頭信息中獲取很多信息. 有兩種方法來獲取. 第一, 許多 [$_SERVER
數組][server]中的值都是由傳來的請求頭信息決定的. 第二, 如果 PHP 是作為 Apache
模塊使用的, apache_request_headers()
會返回一個包含所有請求頭信息的數組 (甚至那些不在 $_SERVER
中的).
安全第一: 不要信任請求頭信息
因為請求頭信息發自瀏覽器, 瀏覽器又可以在客戶端被控制, 所以你永遠不要信任來自請求頭, 又和你站點安全緊密相關的頭信息. 一個很好的例子就是 $_SERVER['HTTP_REFERER']
變量, 這個變量應該包含一個用戶轉自的源 URL. 一個新手的常見錯誤就是認為他們可以使用這個來確保用戶只會通過特定路徑來訪問頁面, 因此他們便無需關心服務器端的數據驗證. 例如, 看看下面的代碼, 它試着去確保數據是從一個特定的頁面發送過來的, 而不是從另一個站點
<?php if($_SERVER['HTTP_REFERER'] != 'http://www.mysite.com/myform.html'){ header('Refresh: 5; url=http://www.mysite.com/myform.html'); echo 'You must use the form on my site...redirecting now.'; } else{ insert_data($_POST['var1'], $_POST['var2']); } ?>
這或許會阻止那些不是很精通的黑客通過他的瀏覽器提交一個自定義的表單來提交數據, 但是任何一個稍微高深一些的黑客都可以通過使用 telnet
來提交數據, 包括請求頭信息
Referer: http://www.mysite.com/myform.html
然后輕易的躲過這層保護機制. 這里所要講的重點是: 使用 HTTP 請求頭信息來統計一些數據以便提供更好的用戶體驗 - 大部分的請求頭信息都是發自真實的瀏覽器而且可以被信任…但是不要在有關安全的問題上依賴任何請求 header
使用 HTTP 請求頭信息
你可以用它做幾件事. 使用 $_SERVER['HTTP_USER_AGENT']
你可以探測用戶生成他使用的什么瀏覽器. 你可以檢查 $_SERVER['HTTP_ACCEPT_LANGUAGE']
(可能要配合 $_SERVER['HTTP_ACCEPT_CHARSET']
和一些 IP 地理位置 ) 來決定向用戶展示什么語言. 雖然 $_SERVER['HTTP_REFERER']
對於安全目的並不能被依賴, 但是可以用來統計你網站的流量, 或者根據用戶的訪問路徑來定制顯示內容. 如果因為某些原因你想要操作原始的請求字符串, 你可以使用 $_SERVER['QUERY_STRING']
. 查看 $_SERVER['REQUEST_METHOD']
可以知道你的頁面是通過 GET
還是 POST
方法訪問的. 還有很多可以幫助你做許多有創意的事情的信息等着你去發現.
HTML meta
標簽中的 HTTP 頭信息 equivalents(對應物)
很有可能在閱讀本文之前, 你已經用過下面的 HTML meta 標簽重定向用戶了:
<meta http-equiv="refresh" content="0;http://www.mysite.com/somepage.html" />
看起來很熟悉? ‘http-equiv’ meta
標簽即 HTTP 響應頭的’對應物’, 引入它們是為了讓沒有服務器端編程能力的人在寫 HTML 頁面的時候也能使用強大的頭信息功能. 使用這些 meta 標簽很簡單: 它們可以被放在文檔 <head>
中的任何地方, http-equiv
屬性包含頭名, content
屬性包含頭值.
我發現這些 meta 標簽最開始也會和 HTTP 頭一樣讓人困惑, 但是現在它們在你看來應該很簡單了. 雖然我更喜歡使用 PHP 的 header()
函數, 但是 meta
標簽的 HTTP equivalents 對於像指定字符集這樣的事情會更順手一些. 比如, 我經常在 HTML 頁面中使用 (有時候 PHP 頁面中也會用到):
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
提示: 使用 meta
標簽來指定頭信息並不被一致的支持, 所以通常來講使用頭信息本身會更加安全和快速. 另外很明顯, 還有一些頭的名值對並不能用 meta equivalents
來指定: 在真正的頭信息被發送, 瀏覽器已經把文檔讀取為 HTML 之后, 你是不能再去設置 Content-Type
成 image/png
的 ;-)
結語
現在我們講完了, 你應該對 HTTP 的工作原理以及如何使用響應請求頭信息以及如何把它們應用到自己的代碼中有了很好的認識. 這些知識也會讓你在 web 應用的效率和安全方面有更審慎的思考. 我希望在你繼續編程的時候, 會發現你使用 HTTP 頭信息更加順手了, 也能通過使用它們讓你的工作更加輕松, 你的頁面更好了.
還有額外一點, 記住頭信息就像是詞語: 它們交流信息並請求某些操作被執行, 但是本身並不強制任何事情. 99.9% 的情況下, 瀏覽器和服務器和諧合作, 事情發展很順利. 但記住在現實中, 是不是你會遇到一些混蛋 (黑客), 或者一些只想按照自己意願做事的東西 (Internet Explorer). web 開發從很多角度講是一個客服性質的工作, 所以你應該盡全力避免這些東西, 滿足客戶的 ‘特殊需要’ :-)