陈力:传智播客古代 珍宝币 泡泡龙游戏开发第37讲:HTTP协议请求(响应)
超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。http请求(get / post),http响应,如果设计防盗链,如何实现文件下载功能。等等内容都是贵阳网站建设的朋友必须要掌握的。
一、什么是HTTP协议
超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。是工作在tcp/ip协议基础上的,所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。
可以看出:http协议是建立在tcp/ip协议基础上,我们的web开发数据的传输都是依赖于http协议,http协议全称是超文本传输协议。
http1.0 短连接 http1.1 长连接。http是TCP/IP协议的一个应用层协议,http也是我们web开发的基础。
二、http协议的-http请求(request):
客户端连上服务器后,向服务器请求某个web资源,称之为客户端向服务器发送了一个HTTP请求。一个完整的HTTP请求包括如下内容:一个请求行、若干消息头、以及实体内容,其中的一些消息头和实体内容都是可选的,消息头和实体内容之间要用空行隔开。
通过httpwatch插件来抓取http请求内容。如下所示:
GET /test/hello.html HTTP/1.1 【表示发送的get请求, 请求资源是/test/hello.html。请求行用于描述客户端的请求方式、请求的资源名称,以及使用的HTTP协议版本号】
消息头用于描述客户端请求哪台主机,以及客户端的一些环境信息等。
Accept: */* 【表示客户端可以接受任何数据】
Referer: http://localhost:80/test/abc.html 【1.表示我是从哪里来】
Accept-Language: zh-cn 【页面语言】
User-Agent: Mozilla/4.0 【告诉服务我的浏览器的内核,操作系统】
Accept-Encoding: gzip, deflate 【表示接受什么样的数据压缩格式.】
Host: localhost:80 【主机:80】
Connection: Keep-Alive 【表示不要立即断掉请求.】
客户端究竟给服务器发送的内容?
如果我这个http1.php. 不希望 192.168.1.33 这个用户访问。
<?php
//print_r($_SERVER);
//foreach($_SERVER as $key=>$val){
// echo "$key=$val <br/>";
//}
//可以指定取出访问该页面的ip
//echo "朋友你的ip是:".$_SERVER['REMOTE_ADDR'];
if($_SERVER['REMOTE_ADDR']=="192.168.1.100"){
//跳转到一个警告页面
header("Location: err.php");
}
?>
在服务器端,我们可以通过$_SERVER来获取我们需要的信息。
重要的有:
HTTP_HOST
REMOTE_ADDR——访问该页面的ip。
DOCUMENT_ROOT——可以获取apche的主目录。
REQUEST_URI——可以获取请求的资源名。
http请求有两种主要的方式get / post:
请求行中的GET称之为请求方式,请求方式有:POST、GET、HEAD、OPTIONS、DELETE、TRACE、PUT
常用的有:POST、GET。
get 和post的区别有哪些?
1)安全性get请求的数据会显示在地址栏上,post请求的数据,放在http协议的消息体。
2)从可以提交数据的大小看:http协议本身并没有限制数据大小。
浏览器在对get和post请求做显示,get 请求数据 2k+35,post没有显示。
传输数据的大小:首先声明:HTTP协议没有对传输的数据大小进行限制,HTTP协议规范也没有对URL长度进行限制。
而在实际开发中存在的限制主要有:
GET:特定浏览器和服务器对URL长度有限制,例如IE对URL长度的限制是2083字节(2K+35)。对于其他浏览器,如Netscape、FireFox等,理论上没有长度限制,其限制取决于操作系统的支持。
因此对于GET提交时,传输数据就会受到URL长度的限制。
POST:由于不是通过URL传值,理论上数据不受限。
3)安全性: 相对而言post提交,安全高。
4)get请求可以更好的添加到收藏夹。
现在我们实际使用一些http请求,完成一个防盗链的练习。
import.php代码:
<?php
//没有防止.
//获取REFERER
if(isset($_SERVER['HTTP_REFERER'])){
//取出来
//判断 $_SERVER['HTTP_REFERER'] 是不是以 http://localhost/http 开始->函数
if(strpos($_SERVER['HTTP_REFERER'],"http://localhost/http")==0){
echo "账号信息:123456789.";
}else{
//跳转到警告页面
header("Location: warning.php");
}
}else{
//跳转到警告页面
header("Location: warning.php");
}
?>
Warning.php代码
<h1>您是非法盗链者!</h1>
a.html代码:
<a href="import.php">查看账号</a>
以上是防盗链的实例。
三、获取HTTP请求头信息:
<?php
$headers = array();
foreach ($_SERVER as $key => $value) {
if ('HTTP_' == substr($key, 0, 5)) {
$headers[str_replace('_', '-', substr($key, 5))] = $value;
echo $key." ".$value."<br/>";
}
}
//也可以显示所有的
echo "*******************也可以显示所有的************************<br/>";
foreach ($_SERVER as $key => $value) {
echo $key." ".$value."<br/>";
}
//指定获取
echo "******************指定获取******************<br/>";
echo "method=".$_SERVER['REQUEST_METHOD']."<br/>";
echo "port1=".$_SERVER['SERVER_PORT']."<br/>";
echo "port2=".$_SERVER['REMOTE_PORT']."<br/>";
?>
********************请求头*********************************<br/>
“PHP_SELF”
当前正在执行脚本的文件名,与 document root相关。举例来说,在URL地址为http://example.com/test.php/foo.bar 的脚本中使用 $_SERVER['PHP_SELF'] 将会得到 /test.php/foo.bar 这个结果。
如果 PHP 以命令行方式运行,该变量无效。
“argv”
传递给该脚本的参数。当脚本运行在命令行方式时,argv 变量传递给程序 C 语言样式的命令行参数。当调用 GET 方法时,该变量包含请求的数据。
“argc”
包含传递给程序的命令行参数的个数(如果运行在命令行模式)。
“GATEWAY_INTERFACE”
服务器使用的 CGI 规范的版本。例如,“CGI/1.1”。
'SERVER_NAME'
当前运行脚本所在服务器主机的名称。如果该脚本运行在一个虚拟主机上,该名称是由那个虚拟主机所设置的值决定。
'SERVER_SOFTWARE'
服务器标识的字符串,在响应请求时的头部中给出。
“SERVER_PROTOCOL”
请求页面时通信协议的名称和版本。例如,“HTTP/1.0”。
“REQUEST_METHOD”
访问页面时的请求方法。例如:“GET”、“HEAD”,“POST”,“PUT”。
“QUERY_STRING”
查询(query)的字符串。
“DOCUMENT_ROOT”
当前运行脚本所在的文档根目录。在服务器配置文件中定义。
“HTTP_ACCEPT”
当前请求的 Accept: 头部的内容。
“HTTP_ACCEPT_CHARSET”
当前请求的 Accept-Charset: 头部的内容。例如:“iso-8859-1,*,utf-8”。
“HTTP_ACCEPT_ENCODING”
当前请求的 Accept-Encoding: 头部的内容。例如:“gzip”。
“HTTP_ACCEPT_LANGUAGE”
当前请求的 Accept-Language: 头部的内容。例如:“en”。
“HTTP_CONNECTION”
当前请求的 Connection: 头部的内容。例如:“Keep-Alive”。
“HTTP_HOST”
当前请求的 Host: 头部的内容。
“HTTP_REFERER”
链接到当前页面的前一页面的 URL 地址。不是所有的用户代理(浏览器)都会设置这个变量,而且有的还可以手工修改 HTTP_REFERER。因此,这个变量不总是正确真实的。
“HTTP_USER_AGENT”
当前请求的 User_Agent: 头部的内容。该字符串表明了访问该页面的用户代理的信息。一个典型的例子是:Mozilla/4.5 [en] (X11; U; Linux 2.2.9 i586)。您也可以使用 get_browser() 得到这个信息。
“REMOTE_ADDR”
正在浏览当前页面用户的 IP 地址。
'REMOTE_HOST'
正在浏览当前页面用户的主机名。反向域名解析基于该用户的 REMOTE_ADDR。
注: 必须配置 Web 服务器来建立此变量。例如 Apache 需要在 httpd.conf 中有 HostnameLookups On。参见 gethostbyaddr()。
“REMOTE_PORT”
用户连接到服务器时所使用的端口。
“SCRIPT_FILENAME”
当前执行脚本的绝对路径名。
“SERVER_ADMIN”
该值指明了 Apache 服务器配置文件中的 SERVER_ADMIN 参数。如果脚本运行在一个虚拟主机上,则该值是那个虚拟主机的值。
“SERVER_PORT”
服务器所使用的端口。默认为“80”。如果你使用 SSL 安全连接,则这个值为您所设置的 HTTP 端口。
“SERVER_SIGNATURE”
包含服务器版本和虚拟主机名的字符串。
“PATH_TRANSLATED”
当前脚本所在文件系统(不是文档根目录)的基本路径。这是在服务器进行虚拟到真实路径的映像后的结果。
“SCRIPT_NAME”
包含当前脚本的路径。这在页面需要指向自己时非常有用。
“REQUEST_URI”
访问此页面所需的 URI。例如,“/index.html”。
“PHP_AUTH_USER”
当 PHP 运行在 Apache 模块方式下,并且正在使用 HTTP 认证功能,这个变量便是用户输入的用户名。
“PHP_AUTH_PW”
当 PHP 运行在 Apache 模块方式下,并且正在使用 HTTP 认证功能,这个变量便是用户输入的密码。
“AUTH_TYPE”
当 PHP 运行在 Apache 模块方式下,并且正在使用 HTTP 认证功能,这个变量便是认证的类型。
在php 的$_SERVER 数组中我们可以获取 一个request_time时间戳(是按照格林威治时间1970-1-1-00到现在的秒数。这个数和time()函数得到是完全一样的),通过下面的时间戳函数可以得到当前时间。
date_default_timezone_set("Asia/Chongqing");
echo "<br/>".date("Y-m-d H:i:s",$_SERVER['REQUEST_TIME'])
*讲解为主 ① 讲Referer 时,用zend建立一个web工程testreferer (a.html, ImportFile.php error.php ) 用httpwath抓取 referer的值, 让学员看看效果,不要深讲 .
If-Modified-Since: 浏览器缓存内容时间
Referer: 来自哪个url 在test apps下建立一个链接测试 【盗链】
***a.html(不放在apahce下)****
<a href=‘http://localhost/test/import.php’>看看账号</a> 【不能浏览】
***a.html(放在apache下)****
<a href=‘/test/import.php’>看看账号</a> 【可以成功浏览】
***import.php**************
<?php
$refer=$_SERVER['HTTP_REFERER'];
if($refer==null||strpos($refer,"http://localhost/test")!=0){
//跳转到错误页面;
header('Location: err.php');
}
echo '个人银行账号!';
?>
***error.php*****
盗链?
****************************如何获取http请求头信息***********************************
<?php
$headers = array();
foreach ($_SERVER as $key => $value) {
if ('HTTP_' == substr($key, 0, 5)) {
$headers[str_replace('_', '-', substr($key, 5))] = $value;
echo $key." ".$value."<br/>";
}
}
//也可以显示所有的
echo "*******************也可以显示所有的************************<br/>";
foreach ($_SERVER as $key => $value) {
echo $key." ".$value."<br/>";
}
//指定获取
echo "******************指定获取******************<br/>";
echo "method=".$_SERVER['REQUEST_METHOD']."<br/>";
echo "port1=".$_SERVER['SERVER_PORT']."<br/>";
echo "port2=".$_SERVER['REMOTE_PORT']."<br/>";
?>
四、Http响应
一个HTTP响应代表服务器向客户端回送的数据,它包括:一个状态行、若干消息头、以及实体内容 ,其中的一些消息头和实体内容都是可选的,消息头和实体内容之间要用空行隔开。
简单定义: 一个Http响应代表服务器给浏览器回送的数据,同时告诉浏览器应当怎样处理数据。
举例:
HTTP/1.1 200 OK(状态行用于描述服务器对请求的处理结果。)
以下是(消息头用于描述服务器的基本信息,以及数据的描述,服务器通过这些数据的描述信息,可以通知客户端如何处理等一会儿它回送的数据。)
Server: Microsoft-IIS/5.0
Date: Thu, 13 Jul 2000 05:46:53 GMT
Content-Length: 2291
Content-Type: text/html
Cache-control: private
(一个空行位置)
以下是实体内容:代表服务器向客户端回送的数据。
<HTML>
<BODY>
快速入门:
HTTP/1.1 200 OK 【200 ok 表示客户端请求成功】
Server: Microsoft-IIS/5.0 【表示告诉浏览器 服务器的情况 】
Date: Thu, 13 Jul 2000 05:46:53 GMT 【告诉浏览器 请求的页面 的时间 】
Content-Length: 2291 【表示回送的数据有 2291个字节】
Content-Type: text/html 【文档类型】
Cache-control: private 【缓存】
hello
五、HTTP响应的细节——状态行:
基本结构:HTTP版本号 状态码 原因叙述<CRLF>
举例:HTTP/1.1 200 OK
状态码用于表示服务器对请求的处理结果,它是一个三位的十进制数。响应状态码分为5类,如下所示:
举例说明Http响应的实际应用。
1)302 告诉浏览器去别的url找资源(转向)。304告诉浏览器资源没有修改,无需再获取。
2)访问 http://localhost:80/test/abcxxx.html演示404错误。
3)500错误还没有找到好的案例。
(1)302状态码的使用
比如我们现在希望访问a.php 页面,让其自动重定向到b.php
<?php
//header(“Location: 新的页面”);
header(“Location: http://www.sohu.com”); // 302状态码也可以让其跳转到外网去。
?>
(2)404 码:404一般说就是该页面不存在,乱输入一个url***则会报404错误。
(3)304码使用:告诉浏览器资源没有修改,无需再获取。
<?php
echo “hello”;
echo “<img src=”Sunset.jpg” width=”100px”>“//在第二次刷新时产生304代码
?>
上面说明了 304的具体用法:
HTTP/1.1 304 Not Modified
Date: Tue, 13 Sep 2011 02:10:38 GMT
Server: Apache/2.2.17 (Win32) PHP/5.3.5
Connection: Keep-Alive
Keep-Alive: timeout=5, max=99
ETag: "12d00000000572c-6f69-3e1d849f35000"
下面是比较详细的一个Http响应头:
Location: http://www.baidu.org/index.php
Server:apache
Content-Encoding: gzip 【内容编码支持gzip压缩算法】
Content-Length: 80 【返回数据大小】
Content-Language: zh-cn
Content-Type: text/html; charset=GB2312
Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT 【表示浏览器请求资源,最新时间】
Refresh: 1;url=http://www.baidu.com 【告诉浏览器,间隔1秒,重定向到 baidu】
Content-Disposition: attachment; filename=aaa.zip
Transfer-Encoding: chunked
Set-Cookie:SS=Q0=5Lb_nQ; path=/search 【讲Cookie】
Expires: -1
Cache-Control: no-cache
Pragma: no-cache
Connection: close/Keep-Alive
Date: Tue, 11 Jul 2000 18:23:51 GMT
演示如何通过Http响应,控制浏览器间隔一定时间去跳转。
<?php
//header(“Refresh: 3 ; url=http://www.sohu.com”);
header(“Refresh: 3 ; url=http://localhost/http/d.php”);
?>
演示如何通过Http响应控制页面缓存,在默认情况下,浏览器会缓存页面。
<?php
//通过header来禁用缓存
header("Expires: -1");
header("Cache-Control: no_cache");
header("Pragma: no-cache");
echo "hello!cache";
?>
代码如下:
<?php
//对函数的说明
//参数说明 $file_name 文件名
// $file_sub_dir: 下载文件的子路径 '"/xxx/xxx/"
function down_file($file_name,$file_sub_dir){
//演示下载一个图片.
//如果文件名是中文,要进行处理
//原因 php文件函数比较古老,需要对中文转码
$file_name=iconv("utf-8","gb2312",$file_name);
//绝对路径通过$_SERVER['DOCUMENT_ROOT']获取
$file_path=$_SERVER['DOCUMENT_ROOT'].$file_sub_dir.$file_name;
if(!file_exists($file_path)){
echo "文件不存在!";
return ;
}
$fp=fopen($file_path,"r");//打开文件
$file_size=filesize($file_path); //获取下载文件的大小
if($file_size>10*1024*1024){
echo "<script language='javascript'>window.alert('文件超过10M,不提供下载!')</script>";
return ;
}
//返回的文件
header("Content-type: application/octet-stream");
header("Accept-Ranges: bytes");//按照字节大小返回
header("Accept-Length: $file_size");//返回文件大小
//这里客户端的弹出对话框,对应的文件名
header("Content-Disposition: attachment; filename=".$file_name);
//向客户端回送数据
$buffer=1024;
//为了下载的安全,我们最好做一个文件字节读取计数器
$file_count=0;
//这句话用于判断文件是否结束,同时通过大小进行判断。
while(!feof($fp) && ($file_size-$file_count>0) ){
$file_data=fread($fp,$buffer);
$file_count+=$buffer; //统计读了多少个字节
echo $file_data; //把部分数据回送给浏览器;
}
fclose($fp); //关闭文件
}
//测试函数是否可用
down_file("照片.jpg","/http/down/");
?>
实例扩展:
1.描述清楚HTTP请求头、响应头的格式。
2.请求头和响应头中各个头字段的含义。
3.请描述200、302、304、404和500等响应状态码所表示的意义。
4.请列举三种禁止浏览器缓存的头字段,并写出相应的。
5.如果浏览器传递给WEB服务器的参数内容超过1K,应该使用那种方式发送请求消息?
6.如何获取http协议的其他消息头信息。
【推荐阅读】陈力:传智播客古代 珍宝币 泡泡龙游戏开发第37讲:HTTP协议请求(响应)