HTTP协议概念及工作流程

74 阅读10分钟

Http协议

重要性:

 无论以后用webservice,还是用rest做大型架构,都离不开对HTTP协议的认识。甚至可以简化的说:
  • webservice = http协议 + XML
  • Rest = http协议 + json
  • 各种API一般是通过 http + XML/jsonXML/json来实现的
  • 做采集,小偷站,也需要对http协议有所了解
  • 以及Ajax对HTTP协议有了了解之后,学习AjaxAjax是非常容易理解的

什么是协议?

计算机中的协议和现实中的协议是一样的,一式双份/多份;双方/多方都尊从共同的一个规范,这个规范就可以称为协议
  • 计算机之所以能够在全世界互通,协议功不可没,如果没有协议,计算机各说各话,便无法互通。计算机中的协议:ftp,http,smtp,pop,tcp/ip协议...
  • http协议即按一定规则,向服务器请求数据或者发送数据,而服务器按一定规则回应数据

Http协议的工作流程

当你打开一个页面时,发生了什么

客户端WEB服务器
apache
Nginx
...
iis
  • 原始状态:客户端和服务器之间没有关系
  • 建立连接,客户端向服务器发送请求
    • 连接:网络上的虚拟电路
  • 沿着连接,服务器向客户端返回响应
    • 客户端收到响应Html代码,解析出图片、文字...
  • 断开连接,虚拟电路消失

问:浏览器能发送HTTP协议,HTTP协议一定要浏览器来发送吗?
答:不是,HTTP既然是一种协议,只要满足这种协议,什么工具都可以发

Http请求信息和响应信息的格式

请求

  1. 请求行
    • 请求方法
      • GET POST HEAD PUT DELETE TRACE OPTIONS
      • HEAD: 和 GET 基本一致,只是不返回内容。例:我们只是确认一个内容(比如照片)还正常存在,不需要返回照片的内容,这时用HEAD比较合适。
      • TRACE:使用代理上网时,想要测试代理有没有修改你的HTTP请求,可以用TRACE来测试,服务器会把最后收到的请求返回给你。
      • OPTIONS:返回服务器可用的请求方法
      • 注意:这些请求方法虽然HTTP协议里规定的,但WEB SERVER未必允许或支持这些方法
    • 请求路径:就是URL的一部分
    • 所用的协议版本
  2. 请求头信息
    • 注意:头信息结束后,有一个空行,头信息和主体信息(如果有),需要这个空行做区分。
    • 即使没有主体信息,空行也不能少。
    • 另:头信息非常丰富,而且丰富的头信息是我们一个学习重点。
  3. 请求主体信息 (可以没有)
    • POST比GET多了主体信息,使用POST时,头信息里要标明 Content-Type:application/x-www-form-urlencoded 和 Content-Lenght

响应

  1. 响应行

    • 协议版本

    • 状态码

      • 用来反映服务器响应情况,最常见的如:
        • 200 -服务器成功返回网页
        • 301/2 -永久/临时重定向
          • 对于一篇新闻,GET请求,重定向无所谓,还能看到原来的内容就行;但如果是POST数据,则会数据丢失。此时可以使用307
        • 307 -重定向中保持原有的请求数据
        • 304 Not Modified -未修改
      • 失败的状态码
        • 404 -请求的网页不存在

        • 503 -服务器暂时不可用

        • 500 -服务器内部错误

        状态码定义说明
        1XX信息接收到请求,继续处理
        2XX成功操作成功地收到,理解和接受
        3XX重定向为了完成请求,必须采取进一步措施
        4XX客户端错误请求的语法有错误或不能完全被满足
        5XX服务器错误服务器无法完成明显有效的请求
    • 状态文字

      • 用来描述状态码,便于人观察
  2. 响应头信息

    • key:value
    • key:value
    • Content-Length:接下来主体的长度
    • / 空行
  3. 响应主体信息 (可以没有)

PHP+socket编程 发送HTTP请求

原理:

  1. 连接某URL的80端口(打开)

  2. 发送头信息(写)

  3. 读取网页内容(读)

socket操作远程的文件和读写本地的文件一样容易,把本地文件看成通过硬件传输,远程文件通过网线传输就行了

抓包(packet capture)就是将网络传输发送与接收的数据包进行截获、重发、编辑、转存等操作,也用来检查网络安全。抓包也经常被用来进行数据截取等。

Cookie

HTTP协议是无状态的,而服务器端的业务必须是要有状态的。cookie可以存储web中的状态信息,以方便服务器端使用。例如判断用户是否是第一次访问网站。

HTTP协议之refer防盗链

服务器怎样知道内容在站外被引用的呢?还有在网站的统计结果里,统计用户从何而来。统计时,是如何得知用户从哪儿来的本网站呢?

  • 在HTTP协议中,头信息里,有一个重要的选项:Referer
  • Referer:代表网页的来源,即上一页的地址
  • 如果是直接在浏览器上输入地址,回车进来,则没有Referer头 这也是为什么服务器知道我们的内容是从哪儿引用的,也知道我们的客户是从哪个网站链接点击进来的

如何配置apache服务器,用于图片防盗链?

原理:

  • 在WEB服务器层面,根据HTTP协议的referer头信息,来判断。如果来自站外,则统一重写到一个很小的防盗链提醒图片上去。

具体步骤:

  1. 打开apache重写模块 mod_rewrite
    • LoadMoudle rewrite_module modules/mod_rewrite.so
    • 前面的“#”去掉,并重启apache
  2. 在需要防盗的网站或目录,写.htaccess文件,并指定防盗链规则 如何指定?
  • 自然是分析referer信息,如果不是来自本站,则重写。 重写规则:
  • 哪种情况重写
    • 是jpeg/jpg/gif/pngjpeg/jpg/gif/png图片时
    • 是referer头与localhost不匹配时
  • 怎么重写
    • 统一rewrite到 某个防盗链图片,如下面的例子
    • RewriteEngine On
      RewriteCond %{REQUEST_FILENAME} .*\.(jpg|jpeg|gif|png) [NC]
      RewriteCond %{HTTP_REFERER} !localhost [NC]
      RewriteRule .* http://www.zixue.it/static/image/common/zixuelogo.png
      

注意:应判断路径或 response 的 mime 头信息 ,来确定内容的类型

HTTP协议缓存控制

我们观察图片的下载,往往是:

  • 第一次请求时 200 ok
  • 第二次请求时 304 Not Modified 未修改状态

在网络上,有一些缓存服务器,另,浏览器自身也有缓存功能。当我们第一次浏览某图片时,正常下载图片,返回值200。基于一个前提 -- 图片不会经常改动,服务器在返回200的同时,还返回该图片的“签名” -- Etag(可以理解为图片的“指纹”)当浏览器再次访问该图片时,去服务器校验“指纹”,如果图片没有变化,直接用缓存中的图片,这样减轻了服务器的负担。

If-Modified-Since:Thu, 17 Mar 2022 07:31:38 GMT
If-None-Match:“xxxxx“

这两行的意思是:

  • 如果 自“Thu, 17 Mar 2022 07:31:38 GMT”这个时间点以后,图片修改过,则重新请求。
  • 如果该图片最新的Etag值和 If-None-Match 的值不匹配,则重新请求。 如果响应信息是304,就意味着浏览器从本地取缓存,节省了图片在网络上传输的时间。

选学 HTTP协议与缓存控制

如果网站比较大,有N台缓存服务器,那么这N台缓存服务器,如何处理主服务器上文件:

  1. 要不要缓存?
  2. 缓存多久? 思考 --- 这说明 缓存服务器与主服务器之间,应该有一些协议,来说明这两个问题?
  • 追问 --- 用什么协议来说明这两个问题?
  • 答 --- 还是http协议,用头信息 cache-control 来控制

利用协议控制缓存

相关模块:mod_expires

例:

 ExpiresActive On
 ExpiresByType image/image/jpeg "access plus 30 days"

如果是在集群环境里,缓存服务器得到此图片,将会认为一个月内有效,减轻了主服务器的负担。

具体用法:

  • 在主服务器,打开 apache 的 expires 扩展,利用该扩展来控制图片、css、html 等文件,控制是否缓存及缓存生命周期。

    • 打开apache模块
      • 找到模块
      • 前面的“#”去掉,并重启apache
  • 在.htaccess中,具体语法如下:

        ExpiresDefault " <base> [plus] {<num> <type>}*"
        ExpiresByType type/encoding " <base> [plus] {<num> <type>}*"
    
    • ExpiresDefault: 设置默认的缓存参数
    • ExpiresByType: 按照文件类型来设置独特的缓存参数
    • 参数:
      1. Base:基于哪个时间点来计算缓存有效期

        • Access/now:基于请求/响应的那一瞬间
        • Modification:基于被请求文件的最后修改日期来计算
      2. Plus关键字是可选的

      3. Num:缓存时间的大小

        • 必须是整数[可以被 atoi() 接受的]
      4. Type:缓存时间的单位

思考 --- 我们能否设置服务器,不让用缓存呢?

  • 比如有些个人信息,不允许缓存服务器缓存,必须到主服务器去请求。

Cache-Control: "no-store,must-revalidate"//这意味着不允许缓存,必须去主服务器验证

可以利用apache的header模块:

<FilesMatch "\.(gif)$">
header set Cache-Control "no-store,must-revalidate"
</FilesMatch>

HTTP协议与内容压缩

ctl + f5 强制刷新

观察:

  • 我们打开163的一篇新闻,响应头信息中 Content-Length 为 36187 个字节
  • 同时,我们点右键保存其源码,得到的文本文件大小为 136428 个字节 思考:
  • Content-Length在之前的学习中,我们知道,代表返回的主题的长度。但此处,为什么返回的主体长度和 content-length 不一致呢?
  • 原因在于:Content-Encoding:gzip 这个响应头信息在作用 原理:
  • 为了提高网页在网络上的传输速度,服务器对主体信息进行压缩。如常见的 gzip 压缩,deflate 压缩,compress 压缩以及 google chrome 正在推的 sdch 压缩。 压缩过程:
  1. 服务器返回压缩内容
  2. 客户端接收压缩
  3. 客户端解压
  4. 客户端渲染页面

刚才那个情况的原因 --- 服务器对页面进行了压缩,而 content-length 是“压缩后”的长度。

如何在 apache 启用压缩功能?

  1. 开启 deflate 模块,或 gzip 模块 (去掉模块前的‘#’)
  2. 在 conf 文件中,写如下代码:
<ifmodule mod_deflate.c>
DeflateCompressionLevel 6 //压缩级别为6,可选1-9,建议为6
AddOutputFilterByType DEFLATE text/plain//压缩文本文件
AddOutputFilterByType DEFLATE text/html//压缩html文件
AddOutputFilterByType DEFLATE text/xml//压缩xml文件
</ifmodule>

为什么要指定文件类型来压缩?

  • 答:压缩也是要耗CPU资源的,图片/视频等文件,压缩效果也不好。一般压缩文本格式的文件。 服务器怎么知道我们的浏览器支持gzip的?
  • 答:客户端允许发一个 Accept-Encoding 头信息,与服务器协商。如:
 Accept-Encoding:gzip,deflate,sdch

小技巧:当我们在采集时,可以不发送 Accept-Encoding 信息,这样采集直接是源码。当然,也可以采集gzip(提高速度),再用 PHP 解压 gzip 的内容。

选学 HTTP协议与分块传输+持久链接 ---> 反向ajax

反向ajax又叫comet,server push 服务器推技术

应用范围:网页聊天服务器,新浪微博在线聊天,google mail 网页聊天,都有用到。

原理:

  • 一般而言,HTTP协议的特点,连接 <-> 断开
  • 具体什么时间断开?
  • 服务器响应 content-length,收到指定的 length 长度的内容时断开
  • 在 http1.1 协议中,允许你不写 content-length ,比如要发送的内容长度确实不知道时
  • 这时,需要一个特殊的 content-type:chunked

分块传输的原理是这样的:

123H\r\n
123H个长度的内容传输给客户端...\r\n
.....
41H\r\n
浏览器继续接收41H长度的内容\r\n
0\r\n (服务器说内容发完了)

把产生的内容,立即送给浏览器而不要等脚本结束再一起送。这样就能达到,即时通信。

服务器端 --- 不间断 --- 推送信息 ---> 到客户端