HTTP Get,Post请求详解

本文由码农网 –
小峰原创,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划!

请求类型

当访问者浏览受保护页面时,客户端浏览器会弹出对话窗口要求用户输入用户名和密码,对用户的身份进行验证,以决定用户是否有权访问页面。下面用两种方法来说明其实现原理。
一、用HTTP标头来实现
标头是服务器以HTTP协议传送HTML信息到浏览器前所送出的字串。HTTP采用一种挑战/响应模式对试图进入受密码保护区域的用户进行身份验证。具体来说,当用户首次向WEB服务器发出访问受保护区域的请求时,挑战进程被启动,服务器返回特殊的401标头,表明该用户身份未经验证。客户端浏览器在检测到上述响应之后自动弹出对话框,要求用户输入用户名和密码。用户完成输入之后点击确定,其身份识别信息就被传送到服务端进行验证。如果用户输入的用户名和密码有效,WEB服务器将允许用户进入受保护区域,并且在整个访问过程中保持其身份的有效性。相反,若用户输入的用户名称或密码无法通过验证,客户端浏览器会不断弹出输入窗口要求用户再次尝试输入正确的信息。整个过程将一直持续到用户输入正确的信息位置,也可以设定允许用户进行尝试的最大次数,超出时将自动拒绝用户的访问请求。
在PHP脚本中,使用函数header()直接给客户端的浏览器发送HTTP标头,这样在客户端将会自动弹出用户名和密码输入窗口,来实现我们的身份认证功能。在PHP中,客户端用户输入的信息传送到服务器之后自动保存在
$PHP_AUTH_USER,$PHP_AUTH_PW,以及
$PHP_AUTH_TYPE这三个全局变量中。利用这三个变量,我们可以根据保存在数据文件或者数据库中用户帐号信息来验证用户身份!
不过,需要提醒使用者注意的是:只有在以模块方式安装的PHP中才能使用$PHP_AUTH_USER,$PHP_AUTH_PW,以及
$PHP_AUTH_TYPE这三个变量。如果用户使用的是CGI模式的PHP则无法实现验证功能。在本节后附有PHP的模块方式安装方法。
下面我们用Mysql数据库来存储用户的身份。我们需要从数据库中提取每个帐号的用户名和密码以便与$PHP_AUTH_USER和$PHP_AUTH_PW变量进行比较,判断用户的真实性。
首先,在MySql中建立一个存放用户信息的数据库 数据库名为XinXiKu
,表名为user;表定义如下: 复制代码
代码如下: create table user NOT NULL AUTO_INCREMENT, name VARCHAR NOT
NULL, password CHAR NOT NULL, PRIMARY KEY 说明:
1、ID为一个序列号,不为零而且自动递增,为主键;
2、name为用户名,不能为空; 3、password为用户密码,不能为空;
以下是用户验证文件login.php 复制代码
代码如下: //判断用户名是否设置 if(!isset {
header(“WWW-Authenticate:Basic realm=”身份验证功能””); header(“HTTP/1.0
401 Unauthorized”); echo “身份验证失败,您无权共享网络资源!”; exit(); }
/*连接数据库*/ $db=mysql_connect(“localhost”,”root”,””); //选择数据库
mysql_select_db; //查询用户是否存在 $result=mysql_query(“SELECT *
FROM user where name=’$PHP_AUTH_USER’ and
password=’$PHP_AUTH_PW'”,$db); if ($myrow = mysql_fetch_row {
//以下为身份验证成功后的相关操作 … } else {
//身份验证不成功,提示用户重新输入 header(“WWW-Authenticate:Basic
realm=”身份验证功能””); header(“HTTP/1.0 401 Unauthorized”); echo
“身份验证失败,您无权共享网络资源!”; exit(); } ?> 程序说明:
在程序中,首先检查变量$PHP_AUTH_USER是否已经设置。如果没有设置,说明需要验证,脚本发出HTTP
401错误号头标,告诉客户端的浏览器需要进行身份验证,由客户端的浏览器弹出一个身份验证窗口,提示用户输入用户名和密码,输入完成后,连接数据库,查询该用用户名及密码是否正确,如果正确,允许登录进行相关操作,如果不正确,继续要求用户输入用户名和密码。
函数说明:
1、isset():用于确定某个变量是否已被赋值。根据变量值是否存在,返回true或false
2、header():用于发送特定的HTTP标头。注意,使用header()函数时,一定要在任何产生实际输出的HTML或PHP代码前面调用该函数。
3、mysql_connect():打开 MySQL 服务器连接。 4、mysql_db_query 到 MySQL
数据库。 5、mysql_fetch_row():返回单列的各字段。
二、用session实现服务器验证
对于需要身份验证的页面,使用apache服务器验证是最好不过的了。但是,apache服务器验证的界面不够友好。而且,cgi模式的php,iis下的php,都不能使用apache服务器验证。这样,我们可以利用session在不同页面间保存用户身份,达到身份验证的目的。
在后端我们同样利用上面的Mysql数据库存放用户信息。
我们先编写一个用户登录界面,文件名为login.php,代码职下: 复制代码 代码如下:
login1.php处理提交的表单,代码如下: 复制代码 代码如下:
$db=mysql_connect(“localhost”,”root”,””); mysql_select_db;
$result=mysql_query(“SELECT * FROM user where name=’$name’ and
password=’$pass'”,$db); if ($myrow = mysql_fetch_row { //注册用户
session_start(); session_register; $user=$myrow[“user”]; //
身份验证成功,进行相关操作 … } else {
echo”身份验证失败,您无权共享网络资源!”; } ?>
这里需要说明的是,用户可以使用在后续的操作中用**
**来绕过身份验证。所以,后续的操作应先检查变量是否注册:已注册,则进行相应操作,否则视为非法登录。相关代码如下:
复制代码 代码如下: session_start(); if
(!session_is_registered { echo “身份验证失败,属于非法登录!”; } else {
//成功登录进行相关操作 … } ?> 附录:PHP以模块方式安装方法
1、首先下载文件:mod_php4-4.0.1-pl2。[如果你的不是PHP4,那么就赶快升级吧!]
解开后有三个文件:mod_php4.dll、mod_php4.conf、readme.txt
2、相关文件拷贝 把mod_php4.dll拷贝到apache安装目录的modules目录下面
把mod_php4.conf拷贝到apache安装目录的conf目录下面
把msvcrt.dll文件拷贝到apache的安装目录下面 3、打开conf/srm.conf文件
,在其中加上一句 Include conf/mod_php4.conf
在做这一些之前请把您的httpd.conf中关于CGI模式的所以设置语句都去掉,即类似下面的部分!
ScripAlias /php4/ “C:/php4/” AddType application/x-httpd-php4 .php
AddType application/x-httpd-php4 .php3 AddType application/x-httpd-php4
.php4 Action application/x-httpd-php4 /php4/php.exe
要想使PHP支持更多的后缀名,没问题。在给出的配置文件mod_php4.conf已经支持了三种后缀名php,php3,php4,如果你还想支持更多的后缀名可以更改这个文件,很简单的。
4、测试 用 phpinfo(); ?> 测试。会看到Server
API的值为apache,而不是cgi ,而且还有有关HTTP Headers Information的信息。

今天要给大家分享一段PHP代码,该代码的功能是用来判断访客是否移动端浏览器访问,该功能的实现思路是通过HTTP_X_WAP_PROFILE、HTTP_VIA、HTTP_USER_AGENT等信息来判断访客是否通过移动端浏览器访问PHP网站。以下是PHP代码:

三种最常见的请求类型是:GET,POST 和 HEAD

/**
 * 是否移动端访问访问
 *
 * @return bool
 */
function isMobile()
{ 
    // 如果有HTTP_X_WAP_PROFILE则一定是移动设备
    if (isset ($_SERVER['HTTP_X_WAP_PROFILE']))
    {
        return true;
    } 
    // 如果via信息含有wap则一定是移动设备,部分服务商会屏蔽该信息
    if (isset ($_SERVER['HTTP_VIA']))
    { 
        // 找不到为flase,否则为true
        return stristr($_SERVER['HTTP_VIA'], "wap") ? true : false;
    } 
    // 脑残法,判断手机发送的客户端标志,兼容性有待提高
    if (isset ($_SERVER['HTTP_USER_AGENT']))
    {
        $clientkeywords = array ('nokia',
            'sony',
            'ericsson',
            'mot',
            'samsung',
            'htc',
            'sgh',
            'lg',
            'sharp',
            'sie-',
            'philips',
            'panasonic',
            'alcatel',
            'lenovo',
            'iphone',
            'ipod',
            'blackberry',
            'meizu',
            'android',
            'netfront',
            'symbian',
            'ucweb',
            'windowsce',
            'palm',
            'operamini',
            'operamobi',
            'openwave',
            'nexusone',
            'cldc',
            'midp',
            'wap',
            'mobile'
            ); 
        // 从HTTP_USER_AGENT中查找手机浏览器的关键字
        if (preg_match("/(" . implode('|', $clientkeywords) . ")/i", strtolower($_SERVER['HTTP_USER_AGENT'])))
        {
            return true;
        } 
    } 
    // 协议法,因为有可能不准确,放到最后判断
    if (isset ($_SERVER['HTTP_ACCEPT']))
    { 
        // 如果只支持wml并且不支持html那一定是移动设备
        // 如果支持wml和html但是wml在html之前则是移动设备
        if ((strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') !== false) && (strpos($_SERVER['HTTP_ACCEPT'], 'text/html') === false || (strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') < strpos($_SERVER['HTTP_ACCEPT'], 'text/html'))))
        {
            return true;
        } 
    } 
    return false;
}

GET:获取一个文档

代码比较完整,有兴趣的同学可以多做一些测试,有任何bug可以在评论中留言。

大部分被传输到浏览器的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_themeheader_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

转载地址:http://hi.baidu.com/%CE%E2_%F0%A9/blog/item/ab29c5e844e63e33b90e2d4a.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注