HTTP基础

161 阅读9分钟

HTTP基础

常见的Http状态码

1xx: 临时性消息

100: 继续发送;101:正在切换协议

2xx: 成功

200:OK;201:创建成功

3xx: 重定向

301:域名永久移动;302:域名暂时移动;304:内容未改变,可以使用本地缓存

4xx:客户端错误

400:Bad Rquest;401:未授权;403:被禁止;404:Not Found

5xx: 服务器错误

500:服务器内部错误;503:服务不可用

Http1和Http1.1的区别

  1. 长连接的支持。Http1.1默认开启了Keep-Alive,以便复用TCP连接

  2. 支持断点续传,即增加了对Range的Header支持,客户端可以指定一个Range,Server只会返回该Range的数据(HTTP状态码是206 Partial Content)。

  3. 支持虚拟主机,即增加了Host的Header支持,客户端填充了Host字段,Server根据Host字段既可以找到指定的容器来处理请求。

HTTP中的Host header指定了请求被发送到的服务器的主机和端口号,允许服务器在单个IP地址和端口号组合上托管多个网站或服务。当客户端向服务器发送请求时,它包括Host header以指示它正在请求服务器上的哪个网站或服务。然后,服务器使用此信息将请求路由到适当的网站或服务。也就是单个对单个服务器部署多个HTTP服务提供了支持。

  1. 新的Http Method的支持,如PUT、DELETE、OPTIONS、TREACE等。

  2. Chunked的支持,Chunked Transfer Encoding的支持使得Http1.1对未知Body大小的请求支持更好。Body发送方将消息分成若干个块,每发送一个块,都会附上当前发送块的大小。当发送完毕时,会附上一个长度为0的块。

  3. Continue(Status Code 100)的支持。当不确定Server是否会接受当前请求,冒然的发送大量数据给Server可能会增加网络流量的消耗,为了解决这个问题,引入了Continue支持。即Client先将相关请求的Header部分告知Server,Server如果愿意接受此请求,则返回Code 100给Client,Client会在当前连接上发送Body数据给Server。

import okhttp3.*;

import java.io.IOException;

public class HttpContinueExample {
    public static void main(String[] args) throws Exception {
        OkHttpClient client = new OkHttpClient();

        RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain"), "Hello, world!");

        Request request = new Request.Builder()
                .url("http://example.com")
                .post(requestBody)
                .header("Expect", "100-continue")
                .build();

        Call call = client.newCall(request);
        Response response = call.execute();

        System.out.println("Response code: " + response.code());
    }
}

我们给Http Request中增加了一个名为Expect的Header,其值为100-contine,那么如果Http服务器支持Http Continue协议,则服务器会先返回一个100的状态码给客户端,客户端才会发送Request的Body部分。

Http 1.1 和 2.0 的特点和区别

多路复用(multiplexing)

Http2支持多路复用。

Http1虽然可以复用连接,但是同一连接上多个请求是串行完成的。为了避免创建过多的连接,默认情况下,Http1.1对于同一个域名,同时发起的请求数量是一定的(如Chrome同域名最大同时请求数量为6个,OKHttp默认值为5个,可以通过client.dispatcher().setMaxRequestsPerHost(${INSERT_HERE}); 进行修改)。

Http2支持多路复用,即在同一个连接上可以同时发起多个请求,如下图:

多路复用

Http2可以很容易的实现多流并行而不用创建多个TCP连接。Http2通信的单元为一个个帧,这些帧就对应着请求和答复的消息,通过帧在一个TCP连接上双向交换消息。

使用Http2协议对应用层来说并不需要做出多么大的改动。Http2将Http的头部消息封装为一个Header帧,将Body部分封装为一个Data帧,所以,Http2可以很好的兼容Http1.1协议。

总结:使用多路复用,减少了TCP连接的数量,降低了服务器的压力,同时避免了TCP慢启动导致的Http1.1效率低下的问题。

首部压缩

Http2使用HPACK算法压缩首部(包括请求的首部和答复的首部),减少包大小,增加通信效率(一般来说,可以达到50%-90%的压缩率)。

服务端推送

Http2的服务端推送指的是服务器在返回客户端请求的同时,主动推送一些客户端可能需要的资源,以提高页面加载速度和用户体验。

HTTP的缺点

  1. 不安全:HTTP通信使用明文,容易被窃听和篡改。(HTTPS进行了改进)
  2. 无状态:HTTP协议本身不会对请求和响应之间的通信状态进行保存,每个请求都是独立的,无法知道前后两个请求是否来自同一个客户端。
  3. 性能较低:HTTP协议在传输数据时,头部信息较多(Http2进行了改进),会占用较大的带宽,导致传输效率较低。
  4. 不支持大文件传输:由于HTTP协议在传输大文件时容易出现错误,因此不适合传输大文件(Http1.1增加了断点续传的支持)。

HTTPS握手过程

参考juejin.cn/post/684790…

第一次握手:

客服端发送自己支持的TLS协议版本、支持的加密套件、支持的压缩方法、以及一个随机数(这是第一个随机数)

服务端返回确认使用的TLS协议版本、确认使用的加密套件、确认的压缩方法、公钥证书、以及一个随机数(这是第二个随机数)

第二次握手:

客户端校验公钥证书的合法性,同时再次生成一个随机数(这是第三个随机数),并将这三个随机数通过固定的算法生成一个字符串,这个字符串即为对称加密的密钥。之后,客户端将这个对称加密的密钥通过公钥证书进行加密,同时将一小段内容使用对称加密密钥完成加密,最后客户端将非对称加密后的密钥和对称加密后的加密内容发送给服务端。

为什么需要发送一小段对称加密的内容给服务端?是因为需要让服务端验证加密密钥的有效性,确保服务端和客户端使用的是同一个对称加密密钥。

服务端验证密钥有效性后,发送成功通知给客户端。

第三次握手:

这次握手是服务端发起,服务端会将一小段内容使用对称加密密钥进行加密,加密后发送给客户端。客户端收到后进行解密,确认解密成功后向服务端发送成功通知。

通过这一次握手,客户端和服务端双方都确认了密钥的一致性,且双方的加解密过程都没有问题。

为什么需要生成三个随机数,一个随机数不行吗?

随机数越多越安全,不管客户端、服务端都可能受到攻击导致可能生成的随机数并非真实的随机数(比如随机数可能被攻击者推导出来),如果客户端、服务端都参与随机数的生成,安全性将进一步提高。

如果业务需求也有类似HTTPS的加密需要,我感觉一个随机数应该也足够了。

为什么需要三次握手,最后一次握手有必要吗?

通过前两次握手,客户端和服务端确认了TLS协议版本、加密套件、压缩算法等,同时确认了对称加密的密钥。最后一次握手主要用于确认客户端的密钥与服务端一致,且客户端能够正常完成解密服务端内容的工作。

HTTPS是一个非常严谨的协议,确保通过多次握手保证过程的绝对安全,尽可能降低被攻击的风险点。

为什么说HTTPS是安全的

HTTPS的安全性首先建立在非对称加密破解的难度极高上,如果非对称加密在未来能够容易的被破解,HTTPS的安全性势必受到挑战。

HTTPS的安全性通常指的是通过HTTPS传递的内容难以被查看,难以被篡改,同时通过HTTPS能够有效的呼啸校验客户端、服务端身份是正确的。

由于HTTPS传输的内容是通过对称加密密钥进行了加密,而对称加密的密钥又通过非对称加密算法进行了加密,也就是攻击者难以拿到对称加密的密钥,所以也难以查看HTTPS传输的内容。连查看都难,篡改自然也就更难了,因为不合法的篡改会导致解密失败,整个通信过程会以失败告终,篡改变得没有意义。

至于身份验证的安全性换一个说法即为:客户端如何判定握手过程收到的公钥证书真的是服务端下发的公钥证书?

公钥证书也是证书,证书里面至少包含这几部分:

  1. 网站域名
  2. 证书持有者
  3. 证书有效期
  4. 证书颁发机构
  5. 服务器公钥(最主要)
  6. 签名

至于包含公钥证书是否是服务端下发的,我们通过域名比对就可以完成判断,关键是如何判定这个证书是否是攻击者伪造的?这就涉及到证书的签名,证书也是通过签名来避免被伪造的。所谓签名也是一个非对称加密的过程,这个非对称加密的私钥只有有限的几家可信任机构存有,而非对称加密的公钥存在于电脑上默认安装的可信任机构颁发的根证书中。当验证公钥证书的有效性时,会通过公钥证书拿到其颁发机构,通过颁发机构找到电脑中对应的根证书,公钥证书通过公钥对证书中的签名进行解密,将解密后的内容同证书中的公开内容(如网站阈值、持有者、颁发机构、证书公钥)进行对比,如果对比通过则说明公钥证书是有效的。

相反,如果伪造证书,因为攻击者不知道根证书的私钥,也就没办法伪造证书中的签名部分,所以伪造的证书不会通过根证书签名验证。

通过以上,我们知道HTTPS的安全性由非对称加密的天然安全性和可信性机构的根证书来保障的。HTTPS的抓包工具都会要求用户安装其自己的根证书,否则其也没办法查看、修改HTTPS的通信内容。