深入剖析 Http 协议

HTTP 顾名思义就是一个协议,但是要从百科上看有点让初学者摸不着头脑,太枯燥,并且也不好结合实际情形去理解。这里用一些小小的事例,争取让大家对HTTP协议有个基本的认知。

1. 首先看一个PHp手册上的示例:

<?php
$fp = fsockopen("www.example.com", 80, $errno, $errstr, 30);
if (!$fp) {
    echo "$errstr ($errno)<br />\n";
} else {
    $out = "GET / HTTP/1.1\r\n";
    $out .= "Host: www.example.com\r\n";
    $out .= "Connection: Close\r\n\r\n";

    fwrite($fp, $out);
    while (!feof($fp)) {
        echo fgets($fp, 128);
    }   
    fclose($fp);
}
?>

运行结果是这样的

HTTP/1.1 200 OK
Cache-Control: max-age=604800
Content-Type: text/html
Date: Sun, 29 May 2016 03:33:38 GMT
Etag: "359670651+gzip+ident"
Expires: Sun, 05 Jun 2016 03:33:38 GMT
Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT
Server: ECS (iad/182A)
Vary: Accept-Encoding
X-Cache: HIT
x-ec-custom-error: 1
Content-Length: 1270
Connection: close

<!doctype html>
<html>
........
........
</html>

上面这个例子是PHP程序模拟普通用户发起一个到 www.example.com 的访问请求。

看的出来请求头各个字段间有一个 \r\n ,这就是协议中其中一小部分。虽然在运行结果中看不到 \r\n ,但是能看到响应头各字段之前使用换行隔开,响应头与响应主体之间有一个空行隔开,这其中都是 \r\n 。空行本省也就是一个 \r\n 的组合 。\r\n 有个专业术语叫做 CRLF,如果看到这4个字母就把它理解为 \r\n 就好。

对于其中的各个请求字段、响应字段都是什么含义,请自行百度,这类型内容比较多,在这里就略过了。其中HTTP基本工作原理也可以参考文章结尾处“HTTP响应报文与工作原理详解”章节,写的比较详细。

2. 接着再看一个post 请求

<?php

$host = 'log.bbs.le.com';
$port = 80; 

$fp = fsockopen($host, $port, $error_no, $error_desc, 30);
if ($fp) {
    $path = '/app/error?a=123456';  
    $data = 'ac=1&bc=2';

    $http_entity_body = $data;
    $http_entity_length = strlen($http_entity_body);
    $http_entity_type = 'application/x-www-form-urlencoded';
    
    $out = ''; 
    $out .= "POST {$path} HTTP/1.1\r\n";
    $out .= "Host: {$host}\r\n";
    $out .= "Content-Type: {$http_entity_type}\r\n";
    $out .= "Content-Length: {$http_entity_length}\r\n";
    $out .= "Connection: close\r\n\r\n";
    $out .= $http_entity_body . "\r\n";
    fputs($fp, $out);

    $d = ''; 
    while (!feof($fp)) {
        $t = fgets($fp, 4096);
        $d .= $t; 
    }   
    fclose($fp);

    echo $d; 
}
?>

运行结果是这样的

HTTP/1.1 200 OK
Server: nginx
Date: Sun, 29 May 2016 05:13:35 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: close
Vary: Accept-Encoding
X-Powered-By: PHP/5.5.10

2
ok
0

与第一个例子中的GET请求对比,这里有几个不一样的地方:

1. 请求头的第一行 ,从 GET 变为了 POST
2. 请求头中加入了 Content-Type ,用来标识数据类型,不然服务端 $_POST 将不解析这个data数据,也就获取不到对应值
3. 请求头中加入了 Content-Length ,用户标识数据长度,这里标识POST传递参数及值的总字符长度,这个如果是POST请求也是必传参数,不然发送到服务端的数据会被截断,得不到预期的结果
4. 请求实体追加在请求头的后面,多了一个空行 \r\n
5. 响应头来自于服务器配置,所以暂时不做定论
6. 响应主体多了 2 0 ,并且与真正的服务端返回数据用换行隔开

第 1-4 条都是http协议的组成部分,也就是说你必须这么做,不然会出现异常的。

第 6 条是什么意思,为什么会多出 2 0 两个字符,经过再三确认,发现这个数字与响应主体长度相关。刚开始认为是不同服务器配置差异导致的,那么我们再模拟一下GET 分别请求动态资源与静态资源试试

<?php

$host = 'log.bbs.le.com';
$port = 80; 

$fp = fsockopen($host, $port, $error_no, $error_desc, 30);
if ($fp) {
    // $path = '/app/error?a=123456';   
    $path = '/test.html';
    
    $out = ''; 
    $out .= "GET {$path} HTTP/1.1\r\n";
    // $out .= "GET {$path} HTTP/1.0\r\n";
    $out .= "Host: {$host}\r\n";
    $out .= "Connection: close\r\n\r\n";
    fputs($fp, $out);

    $d = ''; 
    while (!feof($fp)) {
        $t = fgets($fp, 4096);
        $d .= $t; 
    }   
    fclose($fp);
    echo $d; 
}
?> 

得出的结论是:

GET 请求动态资源同样会加上 2 0 ,而请求静态资源则如同上方的 example.com 的结果一致,那么说明这个 2 0 与动态资源有关。 最终确定这个与Transfer-Encoding: chunked 有直接关系,这表明响应内容按一块一块输出,可以提高响应速度。为了验证这个结果,我们在nginx.conf 的http 段加入以下配置,并重载配置,发现输出结果正常了,没有 2 0 这样的字符了。

chunked_transfer_encoding off;
运行结果是
HTTP/1.1 200 OK
Server: nginx
Date: Sun, 29 May 2016 06:11:22 GMT
Content-Type: text/html
Connection: close
Vary: Accept-Encoding
X-Powered-By: PHP/5.5.10

ok

为什么要对 2 0 这些字符那么在意呢?

因为我们在调用服务端接口是,要获取到响应结果,但是你发现这些字符不是固定的,很是碍事。但是上面的分析只是找到问题发生的原因,基于性能的考虑,transfer-encoding: chunked 还是要开启的。一种解决办法是:把上方的请求头中的 HTTP/1.1 换为 HTTP/1.0,另一种解决办法是推荐使用CURL库来调用服务端接口,这样获取到的结果在 CURL 内部会转换,得到的结果就没有 2 0 这些数字了


相关资料及文献:

HTTP响应报文与工作原理详解 http://network.chinabyte.com/401/13238901.shtml
transfer-encoding:chunked的含义 http://blog.csdn.net/whatday/article/details/7571451
nginx配置关闭chunked http://www.6san.com/759/
HTTP 1.1与HTTP 1.0的比较 http://blog.csdn.net/elifefly/article/details/3964766


标签: http

29
May 2016
AUTHOR WiFeng
CATEGORY Web
COMMENTS No Comments

添加新评论 »

   点击刷新验证码