HTTP笔记

发现写的好乱,内容基本是图解HTTP里的,但感觉讲的确实比较浅,以前我确实也是特意搜过这些,抓包的时候会用到吧~啊哈哈,真的是又乱又杂….

就先这样吧,比如SSL/TLS这种我在公众号写过了,这里就直接不多解释了,解释起来内容也挺多了…..

简单的HTTP协议

如果查看数据包,前两行应该是类似这样的:

1
2
OPTIONS * HTTP/1.1
Host:bfchengnuo.com

OPTIONS方法主要用来查询针对请求URL指定资源支持的方法,*代表的就是不是对特定资源,而是对服务器发起的请求

CONNECT方法要求在与代理服务器通讯时建立隧道,实现用隧道协议进行TCP通信,主要使用SSL/TLS协议把通信内容进行加密然后经过网络隧道传输:CONNECT 代理服务器名:端口号 HTTP版本,后面也就一样了跟Host之类,如果响应为200,那么之后就进入网络隧道了
其实我们常用的也就是GET和POST方法,GET常用于获取,POST用于发送,明显的区别就是GET会把参数放在URL中传送,所以不安全内容大小也有限,但是速度快,POST相反,内容放在请求头中,相对安全

我们知道HTTP是无连接的协议,也就是每进行一次HTTP请求就要断开一次TCP连接,如果访问一个很多图片的网站,除了本身的获取HTML文件需要建立连接、发送请求/响应、断开连接,每一个图片的获取也要都来一遍,这就非常的浪费流量,并且还增加了服务器负载
所以在HTTP/1.1中有了持久连接,就是说,只要任意一端没有明确提出断开连接,则保持TCP连接状态,在1.1中默认都是持久连接,当然是需要客户端(比如浏览器)支持的
支持管线化后可以同时发送多个HTTP请求,使网页加载更快
但毕竟是无连接的协议,在网页跳转之后服务器就不认识你了,在需要记录登陆状态的网站,一般都需要使用Cookie来实现,当发送HTTP请求的时候携带Cookie,服务器再进行对比分析(通过Session),从而确认是谁发起的请求
具体的步骤是:
客户端请求—->服务器生成Cookie,并且通过响应返回给客户端—-客户端在请求中添加Cookie—->服务器知道是这家伙发送的请求
Cookie最大也只能是4KB~存在于请求头中

HTTP报文

HTTP报文有两部分组成,报文首部和报文主体,中间用空行(CR+LF)分割,以访问百度为例
请求报文:

1
2
3
4
5
6
7
8
9
10
11
12
GET / HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
DNT: 1
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.6
Cookie: BAIDUID=241D3FBE4A65352E2607D08762736012:FG=1;省略....太长了
空行

响应报文:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
HTTP/1.1 200 OK
Server: bfe/1.0.8.18
Date: Sat, 11 Mar 2017 07:30:01 GMT
Content-Type: text/html;charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: private
Expires: Sat, 11 Mar 2017 07:30:01 GMT
Content-Encoding: gzip
X-UA-Compatible: IE=Edge,chrome=1
Strict-Transport-Security: max-age=172800
BDPAGETYPE: 2
BDQID: 0x8bb8b8d40000c99a
BDUSERID: 273454118
Set-Cookie: BDSVRTM=111; path=/
空行
html网页内容(报文主体)

为了节省流量,服务器返回的主体可能会进行压缩,比如gzip, deflate方式等,还有一个是identity是不进行编码

  • 分割发送
    因为浏览器必须等到主体后才能加载,当一个网页很大时,那么加载就需要一定时间,页面一片空白,这时可以把主体部分进行分割发送,让浏览器先加载一部分
    分块时每一块都会用16进制来标记块的大小,主体的最后一块使用0(CR+LF)来标记
  • 范围请求
    也就是所说的断点续传,就是可以获取部分内容的请求,比如要获取5001-10000字节内的资源
    在请求头中有:Range:bytes=5001-10000
    与之对应的响应:Content-Range:bytes 5001-10000/10000
    如果是获取从5000以后的全部可以直接5000-这样写,以及可以多重范围:从开始到200以及300以后的就是:-200,300-
    如果服务器支持会返回206 Partial Content的状态码,不支持就返回200 OK并且会返回全部的内容
  • 内容协商
    就是根据你的环境返回最适合的内容,比如使用Accept-Language指明语言为中文,返回的就是中文网页

状态码

  • 1XX: 信息
  • 2XX: 成功
  • 3XX:重定向
    301:永久重定向
    302:临时重定向
    301、302、303返回时,几乎所有浏览器都会把POST改为GET,并删除报文中的主体部分,然后再次发送
    虽然301、302的标准是进制改为GET的
  • 4XX客户端错误
    400:请求是不是写错了?服务器不理解
    401:需要认证并且认证失败
    403:不允许访问
    404:没找到
  • 5XX服务器错误
    503:服务器正忙

详细参考:http://www.w3school.com.cn/tags/html_ref_httpmessages.asp

Web服务器的协作

一台Web服务器是运行部署多个域名的,虽然会被解析到同一台服务器,但是因为Host首部指定了唯一的域名地址,所以是可以正常解析的

  • 代理
    其实就相当于在服务器与客户端之间的中间人,负责转发数据包
  • 网关
    网关是转发其他服务器通信数据的服务器,接收到客户端发来的请求时,像自己拥有资源一样进行处理,客户端甚至感觉不到通信目标是个网关
    网关顾名思义就是连接两个网络的设备,能在网络间转递数据包,主机则不能
    利用网关也可以把HTTP请求转换为其他通信协议
  • 隧道
    简单说就是:相隔较远的服务器和客户端之间进行中转,并保持双方通信连接的程序,隧道本身是透明的
    使用SSL等加密手段确保客户端和服务器进行安全的通信,隧道本身不会去解析HTTP请求,保持原样转发
    隧道协议:将另一个不同的网络协议,封装在负载部分。使用隧道的原因是在不兼容的网络上传输数据,或在不安全网络上提供一个安全路径。
    比如SSH隧道提供一个绕过防火墙,从而连到某些被禁止的互联网服务的的方法。
    被封装的数据包在互联网上传递时所经过的逻辑路径被称为”隧道”。
    隧道可在网络的任一层实现,最常用的是两层:数据链路层和网络层。
  • 缓存
    缓存都会有一个期限,以浏览器为例:当超过后浏览器会向服务器确认是否过期,如果确实失效,然后再重新获取

HTTP首部

主要是HTTP/1.1版本,每隔字段下面其实还细分很多参数,太多了就不贴了,用到的时候去找文档
贴下各首部主要是干什么的

通用首部字段

首部字段名说明
Cache-Control控制缓存的行为(no-cache可以缓存,但需要向服务器确认)
Connection逐跳首部,连接的管理(Keep-Alive持久连接,close关闭连接)
Date创建报文的日期时间
Pragna报文指令
Trailer报文末端的首部一览
Transfer-Encoding指定报文主体的传输编码方式
Upgrade升级为其他协议
Via代理服务器的相关信息
Warning错误通知

请求首部字段

需要说明的是,除了下面的这些 HTTP 头是可以自定义的,在做 RESTful 的时候可能会用到;
在 HTTP 协议本身是没有限制 HTTP 头的大小。尽管如此,很多Web服务器、客户端和代理软件都对HTTP头的大小进行限制。如 Apache2.3 中,每个头的大小最多是8160个字节,一个请求里面最多包含100个头。

首部字段名说明
Accept用户代理可处理的媒体类型(xx;q=0.6, xxx表示权重)
Accept—Charset优先的字符集
Accept-Encoding优先的内容编码
Accept-Language优先的语言(自然语言)
AuthorizationWeb认证信息(证书信息,会返回401)
Expect期待服务器的指定行为
From用户的电子邮箱地址
Host请求资源所在服务器
if-Match比较实体标记(ETag)
if-Modified-Since比较资源的更新时间
if-None-Match比较实体标记(与if-Match相反)
if-Range资源为更新时发送实体Byte的范围请求
if-Unmodified-Since比较资源的更新时间(与if-Modified-Since相反)
Max-Forwards最大传输逐跳数
Proxy-Authorization代理服务器要求客户端的认证信息
Range实体字节范围请求
Referer对请求中的URL的原始获取方法(防盗链)
TE传输编码的优先级
User-AgentHTTP客户端程序的信息

更多可参考:http://dafeizizhu.github.io/2013/07/12/http-header/

响应首部字段

首部字段名说明
Accept-Ranges是否接受字节范围请求
Age推算资源创建经过时间
ETag资源的匹配信息
Location令客户端重定向至指定的URL
Proxy-Authenticate代理服务器对客户端的认证信息
Rety-After对再次发起请求的时机要求
ServerHTTP服务器的安装信息
Vary代理服务器缓存的管理信息
WWW-Authenticate服务器对客户端的认证信息

实体首部字段

首部字段名说明
Allow资源科支持的HTTP方法
Content-Encoding实体主体适用的编码方式
Content-Language实体主体的自然语言
Content-Length实体主体的大小(单位:字节)
Content-Location替代对资源的URL
Content-MD5实体主体的报文摘要
Content-Range实体主体的位置范围
Content-Type实体主体的媒体类型
Expires实体主体过期的日期时间
Last-Modified资源的最后修改日期时间

为Cookie服务的首部字段

首部字段名说明首部类型
Set-Cookie开始状态管理所有的Cookie信息响应首部字段
Cookie服务器接收到的Cookie信息请求首部字段

Set—Cookie字段的属性

属性说明
NAME=VALUE赋予Cookie的名称和其值
expires=DATECookie的有效期(若不mingque指定则默认为浏览器关闭前为止)
path=PATH将服务器上的文件目录作为Cookie的适用对象(若不指定则默认为文档所在的目录)
domain=域名作为Cookie适用对象的域名(若不指定则默认为创建Cookie的服务器的域名,更安全)
Scure仅在HTTPS安全通信时才会发送Cookie
HttpOnly加以限制,使Cookie不能被JavaScript脚本访问

参考:https://ttop5.gitbooks.io/illustration-http/content/chapter6.html

Session与Cookie

关于这个在PHP(二)中提到过,这里再补充下
cookie保存在客户端,session保存在服务器端,session 可以放在 文件(默认)、数据库、或内存中都可以。
它们大多用来保持会话状态,流程类似:
客户端发送认证信息—->服务器认证后生成一个Session然后把ID存到Cookie里返回给客户端
客户端再次请求时携带Cookie—–>服务器验证后确认是真实用户
用户的多数信息可以放在Session中,一方面是因为安全问题,Cookie在客户端可以随意更改;另一方面Cookie只能保存4KB大小,Session随意了,因为一般不会放在内存中

我们知道HTTP是无连接的,当我们从A页面跳到B页面时,HTTP请求肯定是不同的,不同的HTTP请求之间肯定是无法共享数据的,但是Cookie在整个网站的域是可以随意访问的,所以可以利用Cookie来进行保持会话

Session生命周期

Session在用户第一次访问服务器的时候自动创建。需要注意只有访问JSP、Servlet、PHP等后端程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session。
Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。用户每访问服务器一次,无论是否读写Session,服务器都认为该用户的Session“活跃(active)”了一次。
服务器会把长时间内没有活跃的Session从内存/硬盘删除。这个时间就是Session的超时时间。如果超过了超时时间没访问过服务器,Session就自动失效了。
不过有人说当浏览器关闭后(非标签),Session就会销毁,这种是通过什么实现的我没找到….不过我知道服务器为保存SessionID而设置的Cookie是没有有效期的:

Cookie如果没有设置有效期,它的maxAge属性一般为–1,表示仅当前浏览器内有效,关闭浏览器就会失效。
服务器回写的 Cookie 名默认叫 JSESSIONID,注意是有path的,默认为当前应用

所以,当关掉浏览器这个Cookie就失效了,ID也就丢失了,服务器判断一段时间 Session 没有活跃,所以就删除了

更多内容参考:http://www.admin10000.com/document/7097.html

追加协议

HTTP/1.1也有很多的缺点:

  • 一条连接只能发送一个请求
  • 请求只能从客户端开始,客户端不能接收响应外的指令
  • 发送冗长的首部,每次发相同的首部也是浪费流量
  • 非强制压缩,有可能未经压缩就发送

如果是一个对实时更新要求比较高的网站,服务器端更新了在没有请求的情况下不能发送给客户端,只能客户端不断的去请求,发送大量重复的首部,每次返回的都是全部的内容

  • Ajax
    核心技术是XMLHttpRequest的API,通过JS脚本就可以和服务器进行HTTP通信,从而实现在加载完的页面上发送请求,并且进行局部更新
  • Comet
    通常,服务器收到请求,处理完毕后会立即返回响应,但是Comet会将响应置于挂起状态,一旦服务器更新了再返回响应,这样也就是说,一次连接的时间边长了

但是以上两种并没有解决HTTP本身的问题,还是会发送大量的重复首部,后来有了Google的SPDY
SPDY工作在会话层,也就是TCP(SSL)和HTTP之间,还是采用HTTP建立连接,考虑到安全性规定使用SSL,它做到了:

  • 单路复用
    在单一的TCP连接上可以处理多个HTTP请求
  • 赋予请求优先级
  • 压缩HTTP首部
  • 推送功能
    服务器可以直接发送数据给客户端,不用等待客户端的请求
  • 服务器提示
    主体提示客户端请求的所需资源,在客户端请求资源前就知道了资源的存在,减少了请求

WebSocket协议

也是为了解决HTTP协议的瓶颈,它支持发送任意类型的数据,推送功能,会一直保持连接状态所以也就可以进行全双工通信,可以直接向客户端发送数据

建立WebSocket还是用的HTPP,在首部加入Upgrade:websocket;Connection:Upgrade,服务器收到后返回101 Switching Protocols然后双方就开始使用WebSocket进行通信了

评论框加载失败,无法访问 Disqus

你可能需要魔法上网~~