Java 高阶之 Http 协议和 Https 协议

Http 报文

Http 报文可以分为请求报文和响应报文,格式大同小异。
请求报文格式:

  



响应报文格式:

  



格式标签解释:

 指请求方法,常用的主要是Get、 Post、Head 等。
 指协议版本,现在通常都是Http/1.1了

 请求地址

 指响应状态码, 如 200、404等

 原因短语,200 OK 、404 Not Found 这种后面的描述就是原因短语,通常不必太关注。

请求方法

最常用的有 Get 和 Post两种,面试时也常常会问到这两者有什么区别,通常什么情况下使用?

  • 传输形式上:通过 Get 方法发起请求时,会将请求参数拼接在 request-url 尾部,格式是 url?param1=xxx¶m2=xxx&[…]。我们需要知道,这样传输参数会使得参数都暴露在地址栏中。并且由于 url 是 ASCII 编码的,所以参数中如果有 Unicode 编码的字符,例如汉字,都会编码之后传输。另外值得注意的是,虽然 http 协议并没有对 url 长度做限制,但是一些浏览器和服务器可能会有限制,所以通过 Get 方法发起的请求参数不能够太长。而通过 Post 方法发起的请求是将参数放在请求体中的,所以不会有 Get 参数的这些问题。

  • 方法本身的语义上:Get 方法通常是指从服务器获取某个 URL 资源,其行为可以看作是一个读操作,对同一个 URL 进行多次 Get 并不会对服务器产生什么影响。而 Post 方法通常是对某个 URL 进行添加、修改,例如一个表单提交,通常会往服务器插入一条记录。多次 Post 请求可能导致服务器的数据库中添加了多条记录。
    Http协议中的get和post

状态码

常见的状态码主要有:

  • 200 OK
    请求成功,实体包含请求的资源
  • 301 Moved Permanent
    请求的URL被移除了,通常会在Location首部中包含新的URL用于重定向。
  • 304 Not Modified
    条件请求进行再验证,资源未改变。
  • 404 Not Found
    资源不存在
  • 206 Partial Content
    成功执行一个部分请求。这个在用于断点续传时会涉及到。

请求头

在请求报文和响应报文中都可以携带一些信息,通过与其他部分配合,能够实现各种强大的功能。这些信息位于起始行之下与请求实体之间,以键值对的形式,称之为首部。每条首部以回车换行符结尾,最后一个首部额外多一个换行,与实体分隔开。
Date
Cache-Control
Last-Modified
Etag
Expires
If-Modified-Since
If-None-Match
If-Unmodified-Since
If-Range
If-Match

实体

请求发送的资源,或是响应返回的资源。

Http 缓存

当我们发起一个 http 请求后,服务器返回所请求的资源,这时我们可以将该资源的副本存储在本地,这样当再次对该 url 资源发起请求时,我们能快速的从本地存储设备中获取到该 url 资源,这就是所谓的缓存。缓存既可以节约不必要的网络带宽,又能迅速对http请求做出响应。
新鲜度检测
当我们发起一个请求时,我们需要先对缓存的资源进行判断,看看究竟我们是否可以直接使用该缓存资源,这个就叫做新鲜度检测。

再验证
如果发现该缓存资源已经超过了一定的时间,我们再次发起请求时不会直接将缓存资源返回,而是先去服务器查看该资源是否已经改变,这个就叫做再验证。

再验证命中
如果服务器发现对应的url资源并没有发生变化,则会返回 304 Not Modified,并且不再返回对应的实体。这称之为再验证命中。相反如果再验证未命中,则返回 200 OK,并将改变后的url资源返回,此时缓存可以更新以待之后请求。

实现方式

  1. 新鲜度检测
    我们需要通过检测资源是否超过一定的时间,来判断缓存资源是否新鲜可用。那么这个一定的时间怎么决定呢?其实是由服务器通过在响应报文中增加Cache-Control:max-age,或是Expire这两个首部来实现的。值得注意的是Cache-Control是http1.1的协议规范,通常是接相对的时间,即多少秒以后,需要结合last-modified这个首部计算出绝对时间。而Expire是http1.0的规范,后面接一个绝对时间。

  2. 再验证
    如果通过新鲜度检测发现需要请求服务器进行再验证,那么我们至少需要告诉服务器,我们已经缓存了一个什么样的资源了,然后服务器来判断这个缓存资源到底是不是与当前的资源一致。逻辑是这样没错。那怎么告诉服务器我当前已经有一个备用的缓存资源了呢?我们可以采用一种称之为条件请求的方式实现再验证。

  3. Http定义了5个首部用于条件请求:
    If-Modified-Since
    If-None-Match
    If-Unmodified-Since
    If-Range
    If-Match

Https

简单的说 Http + 加密 + 认证 + 完整性保护 = Https

传统的 Http 协议是一种应用层的传输协议,Http 直接与 TCP 协议通信。其本身存在一些缺点:

Http 协议使用明文传输,容易遭到窃听。

Http 对于通信双方都没有进行身份验证,通信的双方无法确认对方是否是伪装的客户端或者服务端。

Http 对于传输内容的完整性没有确认的办法,往往容易在传输过程中被劫持篡改。

因此,在一些需要保证安全性的场景下,比如涉及到银行账户的请求时,Http 无法抵御这些攻击。
Https 则可以通过增加的 SSL\TLS,支持对于通信内容的加密,以及对通信双方的身份进行验证。

Https的加密
加密的方式主要有两类:

  • 对称秘钥加密

  • 非对称秘钥加密

对称秘钥加密是指加密与解密过程使用同一把秘钥。这种方式的优点是处理速度快,但是如何安全的从一方将秘钥传递到通信的另一方是一个问题。

非对称秘钥加密是指加密与解密使用两把不同的秘钥。这两把秘钥,一把叫公开秘钥,可以随意对外公开。一把叫私有秘钥,只用于本身持有。得到公开秘钥的客户端可以使用公开秘钥对传输内容进行加密,而只有私有秘钥持有者本身可以对公开秘钥加密的内容进行解密。这种方式克服了秘钥交换的问题,但是相对于对称秘钥加密的方式,处理速度较慢。

SSL\TLS 的加密方式则是结合了两种加密方式的优点。首先采用非对称秘钥加密,将一个对称秘钥使用公开秘钥加密后传输到对方。对方使用私有秘钥解密,得到传输的对称秘钥。之后双方再使用对称秘钥进行通信。这样即解决了对称秘钥加密的秘钥传输问题,又利用了对称秘钥的高效率来进行通信内容的加密与解密。

Https的认证

SSL\TLS 采用的混合加密的方式还是存在一个问题,即怎么样确保用于加密的公开秘钥确实是所期望的服务器所分发的呢?也许在收到公开秘钥时,这个公开秘钥已经被别人篡改了。因此,我们还需要对这个秘钥进行认证的能力,以确保我们通信的对方是我们所期望的对象。

目前的做法是使用由数字证书认证机构颁发的公开秘钥证书。服务器的运营人员可以向认证机构提出公开秘钥申请。认证机构在审核之后,会将公开秘钥与共钥证书绑定。服务器就可以将这个共钥证书下发给客户端,客户端在收到证书后,使用认证机构的公开秘钥进行验证。一旦验证成功,即可知道这个秘钥是可以信任的秘钥。

总结

Https的通信流程:

  • Client发起请求

  • Server 端响应请求,并在之后将证书发送至 Client

  • Client使用认证机构的共钥认证证书,并从证书中取出Server端共钥。

  • Client 使用共钥加密一个随机秘钥,并传到 Server

  • Server 使用私钥解密出随机秘钥

通信双方使用随机秘钥最为对称秘钥进行加密解密。

你可能感兴趣的:(Java 高阶之 Http 协议和 Https 协议)