HTTP Header 入门详解

HTTP Header 入门详解(转真的不错)

什么是HTTP Headers

HTTP是“Hypertext Transfer Protocol”的所写,整个www都在使用这种协定,几乎你在流览器里看到的大部分内容都是通过http协定来传输的,比如这篇文章。

HTTP Headers是HTTP请求和相应的核心,它承载了关于用户端流览器,请求页面,伺服器等相关的资讯。

HTTP Header 入门详解_第1张图片


示例

当你在流览器位址栏里键入一个url,你的流览器会将类似如下的http请求:

GET /tutorials/other/top-20-mysql-best-practices/ HTTP/1.1 (Request line) Host: net.tutsplus.com 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 Cookie: PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120 Pragma: no-cache Cache-Control: no-cache

第一行被称为“Request Line” 它描述的是这个请求的基本资讯,剩下的就是HTTP headers了。

请求完成之后,你的流览器可能会收到如下的HTTP回应:

HTTP/1.x 200 OK (state line) Transfer-Encoding: chunked Date: Sat, 28 Nov 2009 04:36:25 GMT Server: LiteSpeed Connection: close X-Powered-By: W3 Total Cache/0.8 Pragma: public Expires: Sat, 28 Nov 2009 05:36:25 GMT Etag: "pub1259380237;gz" Cache-Control: max-age=3600, public Content-Type: text/html; charset=UTF-8 Last-Modified: Sat, 28 Nov 2009 03:50:37 GMT X-Pingback: http://net.tutsplus.com/xmlrpc.php Content-Encoding: gzip Vary: Accept-Encoding, Cookie, User-Agent <!-- ... rest of the html ... -->

第一行被称为“Status Line”,它之后就是http headers,空行完了就开始输出内容了(在这个案例中是一些html输出)。

但你查看页面源代码却不能看到HTTP headers,虽然它们连同你能看到的东西一起被传送至流览器。

这个HTTP请求也发出了一些其他资源的接收请求,例如图片,css档,js文件等等。

下面我们来看看细节。

怎样才能看到HTTP Headers

下面这些FireFox扩展能够帮助你分析HTTP headers:

1. firebug

HTTP Header 入门详解_第2张图片

2. Live HTTP Headers

HTTP Header 入门详解_第3张图片

3. 在PHP中:

  • getallheaders()用来获取请求Header.你也可以使用$_SERVER阵列.
  • headers_list()用来获取回应Header.

文章下面将会看到一些使用php示范的例子。

HTTP Request 的结构

HTTP Header 入门详解_第4张图片

被称作“first line”的第一行包含三个部分:

  • “method” 表明这是何种类型的请求. 最常见的请求类型有GET, POST 和HEAD.
  • “path” 体现的是主机之后的路径. 例如,当你请求“http://net.tutsplus.com/tutorials/other/top-20-mysql-best-practices/”时, path 就会是“/ tutorials/other/top-20-mysql-best-practices/”.
  • “protocol” 包含有“HTTP” 和版本号, 目前流览器都会使用1.1.

剩下的部分每行都是一个“Name:Value”对。它们包含了各式各样关于请求和你流览器的资讯。

例如”User-Agent“就表明了你流览器版本和你所用的作业系统。

”Accept-Encoding“会告诉伺服器你的流览可以接受类似gzip的压缩输出。

这些headers大部分都是可选的。HTTP 请求甚至可以被精简成这样子:

GET /tutorials/other/top-20-mysql-best-practices/ HTTP/1.1 
Host: net.tutsplus.com

并且你仍旧可以从伺服器收到有效的回应。

请求类型

三种最常见的请求类型是:GET,POST 和HEAD ,从html的编写过程中你可能已经熟悉了前两种。

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 Header,它提供了发送资讯的相关资讯.
  • 所有资料都在headers之后,以查询字串的形式被发送.

POST方式的请求也可用在AJAX,应用程式,cURL … 之上。并且所有的档上传表单都被要求使用POST方式。

HEAD :接收Header资讯

HEAD和GET很相似,只不过HEAD不接受HTTP回应的内容部分。当你发送了一个HEAD请求,那就意味着你只对HTTPHeader感兴趣,而不是文档本身。

这个方法可以让流览器判断页面是否被修改过,从而控制缓存。也可判断所请求的文档是否存在。

例如,假如你的网站上有很多链结,那么你就可以简单的给他们分别发送HEAD请求来判断是否存在死链,这比使用GET要快很多。

http 回应结构

当流览器发送了HTTP请求之后,伺服器就会通过一个HTTP response来回应这个请求。如果不关心内容,那么这个请求看起来会是这样的:

HTTP Header 入门详解_第5张图片

第一个有价值的资讯就是协定。目前伺服器都会使用HTTP/1.x 或者HTTP/1.1。

接下来一个简短的资讯代表状态。代码200意味着我们的请求已经发送成功了,伺服器将会返回给我们所请求的文档,在Header资讯之后。

我们都见过“404”页面。当我向伺服器请求一个不存在的路径时,伺服器就用用404来代替200回应我们。

余下的回应内容和HTTP请求相似。这些内容是关于伺服器软体的,页面/档何时被修改过,mime type 等等…

同样,这些Header资讯也是可选的。

HTTP 状态码

  • 200 用来表示请求成功.
  • 300 来表示重定向.
  • 400 用来表示请求出现问题.
  • 500 用来表示伺服器出现问题.

200 成功(OK)

前文已经提到,200是用来表示请求成功的。

206 部分内容(Partial Content)

如果一个应用只请求某范围之内的档,那么就会返回206.

这通常被用来进行下载管理,中断点续传或者档分块下载。

404 没有找到(Not Found)

HTTP Header 入门详解_第6张图片

很容易理解

401 未经授权(Unauthorized)

受密码保护的页面会返回这个状态。如果你没有输入正确的密码,那么你就会在流览器中看到如下的资讯:

HTTP Header 入门详解_第7张图片

注意这只是受密码保护页面,请求输入密码的弹出框是下面这个样子的:

HTTP Header 入门详解_第8张图片

403 被禁止(Forbidden)

如果你没有许可权访问某个页面,那么就会返回403状态。这种情况通常会发生在你试图打开一个没有index页面的档夹。如果伺服器设置不允许查看目录内容,那么你就会看到403错误。

其他一些方式也会发送许可权限制,例如你可以通过IP位址进行阻止,这需要一些htaccess的协助。

order allow,deny deny from 192.168.44.201 deny from 224.39.163.12 deny from 172.16.7.92 allow from all

302 (或307)临时移动(Moved Temporarily)和301永久移动(Moved Permanently)

这两个状态会出现在流览器重定向时。例如,你使用了类似bit.ly 的网址缩短服务。这也是它们如何获知谁点击了他们链结的方法。

302和301对于流览器来说是非常相似的,但对于搜索引擎爬虫就有一些差别。打个比方,如果你的网站正在维护,那么你就会将用户端流览器用302重定向到另外一个位址。搜索引擎爬虫就会在将来重新索引你的页面。但是如果你使用了301重定向,这就等于你告诉了搜索引擎爬虫:你的网站已经永久的移动到了新的位址。

500 伺服器错误(Internal Server Error)

HTTP Header 入门详解_第9张图片

这个代码通常会在页面脚本崩溃时出现。大部分CGI脚本都不会像PHP那样输出错误资讯给流览器。如果出现了致命的错误,它们只会发送一个500的状态码。这时需要查看伺服器错误日志来排错。

完整的列表

你可以在这里找到完整的HTTP状态码说明。

HTTP Headers 中的HTTP请求

现在我们来看一些在HTTP headers中常见的HTTP请求资讯。

所有这些Header资讯都可以在PHP的$_SERVER阵列中找到。你也可以用getallheaders()函数一次性获取所有的Header资讯。

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)

这个Header可以携带如下几条资讯:

  • 流览器名和版本号.
  • 作业系统名和版本号.
  • 默认语言.

这就是某些网站用来收集访客资讯的一般手段。例如,你可以判断访客是否在使用手机访问你的网站,然后决定是否将他们引导至一个在低解析度下表现良好的移动网站。

在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

如果一个页面已经在你的流览器中被cache,那么你下次流览时流览器将会检测文档是否被修改过,那么它就会发送这样的Header:

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

顾名思义, Header将会包含referring url信息。

例如,我访问Nettuts+的主页并点击了一个链结,这个Header资讯将会发送到流览器:
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.

Authorization

当一个页面需要授权,流览器就会弹出一个登入视窗,输入正确的帐号后,流览器会发送一个HTTP请求,但此时会包含这样一个Header:

Authorization: Basic bXl1c2VyOm15cGFzcw==

包含在Header的这部分资讯是base64 encoded。例如,base64_decode('bXl1c2VyOm15cGFzcw==') 会被转化为'myuser:mypass' 。

在PHP中,这个值可以用$_SERVER['PHP_AUTH_USER'] 和$_SERVER['PHP_AUTH_PW'] 获得。

更多细节我们会在WWW-Authenticate部分讲解。

HTTP Headers 中的HTTP回应

现在让我了解一些常见的HTTP Headers中的HTTP回应资讯。

在PHP中,你可以通过header()来设置Header回应资讯。PHP已经自动发送了一些必要的Header资讯,如载入的内容,设置cookies等等…你可以通过headers_list()函数看到已发送和将要发送的Header资讯。你也可以使用headers_sent()函数来检查Header资讯是否已经被发送。

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”意味着这个回应可以被任何人cache,“max-age” 则表明了该cache有效的秒数。允许你的网站被cache降大大减少下载时间和带宽,同时也提高的流览器的载入速度。

也可以通过设置“no-cache” 指令来禁止缓存:

Cache-Control: no-cache

更多详情请参见w3.org

Content-Type

这个Header包含了文档的”mime-type”。流览器将会依据该参数决定如何对文档进行解析。例如,一个html页面(或者有html输出的php页面)将会返回这样的东西:

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

'text' 是文档类型,'html'则是文档子类型。这个Header还包括了更多资讯,例如charset。

如果是一个图片,将会发送这样的回应:

Content-Type: image/gif

流览器可以通过mime-type来决定使用外部程式还是自身扩展来打开该文档。如下的例子降调用Adobe Reader:

Content-Type: application/pdf

直接载入,Apache通常会自动判断文档的mime-type并且添加合适的资讯到Header去。并且大部分流览器都有一定程度的容错,在Header未提供或者错误提供该资讯的情况下它会去自动检测mime-type。

你可以在这里找到一个常用mime-type列表。

在PHP中你可以通过finfo_file()来检测档的ime-type。

Content-Disposition

这个Header资讯将告诉流览器打开一个档下载视窗,而不是试图解析该回应的内容。例如:

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

他会导致流览器出现这样的对话方块:

HTTP Header 入门详解_第10张图片

注意,适合它的Content-Type头资讯同时也会被发送

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

Content-Length

当内容将要被传输到流览器时,伺服器可以通过该Header告知流览器将要传送档的大小(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  & lt ;  1000 ;  $i ++ )  {  echo  str_repeat ( "." , 1000 ) ;  // sleep to slow down the download  usleep ( 50000 ) ;  }

结果将会是这样的:

HTTP Header 入门详解_第11张图片

现在,我将Content-LengthHeader注释掉:

// 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  & lt ;  1000 ;  $i + + )  {  echo  str_repeat ( "." , 1000 ) ;  // sleep to slow down the download  usleep ( 50000 ) ;  }

结果就变成了这样:

HTTP Header 入门详解_第12张图片

这个流览器只会告诉你已下载了多少,但不会告诉你总共需要下载多少。而且进度条也不会显示进度。

Etag

这是另一个为缓存而产生的Header资讯。它看起来会是这样:

Etag: “pub1259380237;gz”

伺服器可能会将该资讯和每个被发送档一起回应给流览器。该值可以包含文档的最后修改日期,档大小或者档校验和。流览会把它和所接收到的文档一起缓存。下一次当流览器再次请求同一档时将会发送如下的HTTP请求:

If-None-Match: “pub1259380237;gz”

如果所请求的文档Etag值和它一致,伺服器将会发送304状态码,而不是200。并且不返回内容。流览器此时就会从缓存载入该档。

Last-Modified

顾名思义,这个Header资讯用GMT格式表明了文档的最后修改时间:

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

$modify_time = filemtime($file); 
header(“Last-Modified: ” . gmdate(“D, d MYH:i:s”, $modify_time) . ” GMT”);

它提供了另一种缓存机制。流览器可能会发送这样的请求:

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

在If-Modified-Since一节我们已经讨论过了。

Location

这个Header是用来重定向的。如果回应代码为301 或者302 ,伺服器就必须发送该Header。例如,当你访问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);

Set-Cookie

当一个网站需要设置或者更新你流览的cookie资讯时,它就会使用这样的Header:

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会作为单独的一条Header资讯。注意,通过js设置cookie将不会出现在HTTP头中。

在PHP中,你可以通过setcookie()函数来设置cookie,PHP会发送合适的HTTP头。

setcookie(“TestCookie”, “foobar”);

它会发送这样的头资讯:

Set-Cookie: TestCookie=foobar

如果未指定到期时间,cookie就会在流览器关闭后被删除。

WWW-Authenticate

一个网站可能会通过HTTP发送这个Header资讯来验证用户。当流览器看到Header有这个回应时就会打开一个弹出窗。

WWW-Authenticate: Basic realm=”Restricted Area”

它会看起来像这样:

HTTP Header 入门详解_第13张图片

PHP手册的一章中就有一段简单的代码演示了如果用PHP做这样的事情:

if  ( ! isset ( $_SERVER [ 'PHP_AUTH_USER' ] ) )  {  header ( 'WWW-Authenticate: Basic realm="My Realm"' ) ;  header ( 'HTTP/1.0 401 Unauthorized' ) ;  echo  'Text to send if user hits Cancel button' ;  exit ;  }  else  {  echo

Hello {$_SERVER['PHP_AUTH_USER']}.

;  echo

You entered {$_SERVER['PHP_AUTH_PW']} as your password.

;   }

Content-Encoding

这个Header通常会在返回内容被压缩时设置。

你可能感兴趣的:(HTTP Header 入门详解)