问题

  • http协议是什么协议,结构是什么样的?
  • http协议是几层协议?
  • http是有状态的还是无状态的?
  • nginx是几层代理?
  • lvs是几层代理?
  • 浏览器在与服务器建立了tcp连接后是否会在一个 HTTP 请求完成后断开?什么情况下会断开?
  • 一个 TCP 连接可以发送几个 HTTP 请求?
  • 一个 TCP 连接中 HTTP 请求发送可以一起发送么(比如一起发三个请求,再三个响应一起接收)?
  • 为什么有的时候刷新页面不需要重新建立 SSL 连接?
  • 浏览器对同一 Host 建立 TCP 连接到数量有没有限制?

sktools介绍

./sktools -a tcp -host 61.135.169.125 -port 80
GET / HTTP/1.1
Host: www.baidu.com


http协议

以下所有的验证基于http1.1

http协议是什么

HTTP 是超文本传输协议,也就是 HyperText Transfer Protocol。

http版本

  • HTTP/0.9 是个简单的文本协议,只能获取文本资源;
  • HTTP/1.0 确立了大部分现在使用的技术,但它不是正式标准;
    • 增加了 HEAD、POST 等新方法;
    • 增加了响应状态码,标记可能的错误原因;
    • 引入了协议版本号概念;
    • 引入了 HTTP Header(头部)的概念,让 HTTP 处理请求和响应更加灵活;
    • 传输的数据不再仅限于文本
  • HTTP/1.1 是目前互联网上使用最广泛的协议,功能也非常完善;
    • 增加了 PUT、DELETE 等新的方法;
    • 增加了缓存管理和控制;
    • 明确了连接管理,允许持久连接;
    • 允许响应数据分块(chunked),利于传输大文件;
    • 强制要求 Host 头,让互联网主机托管成为可能。
  • HTTP/2 基于 Google 的 SPDY 协议,注重性能改善,但还未普及;
    • 二进制协议,不再是纯文本;
    • 可发起多个请求,废弃了 1.1 里的管道;
    • 使用专用算法压缩头部,减少数据传输量;
    • 允许服务器主动向客户端推送数据;
    • 增强了安全性,“事实上”要求加密通信。
  • HTTP/3 基于 Google 的 QUIC 协议,是将来的发展方向。

http是几层协议

七层 or 四层

http是有状态的还是无状态的

http是无状态,可通过Cookie + session的形式记录状态

WX20200702-171008@2x

response set到客户端保存的coolie数据,在客户请求时,会将所有的cookie上传至服务器

http报文结构

  • 请求报文
    WX20200628-161655@2x-1
POST /xxl/login HTTP/1.1
Content-Type: application/json
User-Agent: PostmanRuntime/7.25.0
Accept: */*
Cache-Control: no-cache
Postman-Token: 6f7e191e-6753-4c38-a501-9c548b0ba606
Host: b2c-qa.kanche.com
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 9

{"a":"b"}
  • 响应报文
    WX20200628-162846@2x
HTTP/1.1 200 OK
Connection: close
Transfer-Encoding: chunked
Content-Type: application/json;charset=UTF-8
Date: Sun, 28 Jun 2020 08:46:23 GMT
X-Application-Context: trade-application-gateway:8080

39
{"code":500,"msg":"账号或密码为空","content":null}
  • 在响应结构header及body间存在一个数字39,该数字为http body length表示http response body体存在57个字符(39为16进制)
  • 正常response 报文是无body length,此处存在是由于response header Transfer-Encoding为chunked

http长连接

测试接口http://localhost:8080/spring-tomcat/keepalive?sleep=10

  • tomcat配置,下面两个参数未找到spring boot的配置,可自定义实现,实现代码见附1
    • KeepAliveTimeout:设置长连接的时间,该时间后无新的请求,则关闭连接
    • MaxKeepAliveRequests:该连接处理http请求的个数
  • 浏览器,postman等支持 长连接,而curl执行完了后,会关掉程序,所以无法验证长连接
  • 除了上述两个配置,还有个和timeout相关的配置为ConnectionTimeout,经过多次测试,该参数为网络等待处理的时间,如 等待发送http请求的时间,等待接收http报文的时间,而KeepAliveTimeout为两次请求的间隔时间,KeepAliveTimeout的默认值为ConnectionTimeout

长连接的关键不只是服务端的配置,客户端是否实现了重复使用链接同样重要

postman连接

  • postman 请求api接口多次,发现使用同一连接
    WX20200630-181450@2x
  • postman connection为close 请求api接口多次,发现每次请求都需要重新创建tcp连接
    WX20200630-182119@2x

浏览器连接

需要注意的是一个浏览器可以对同一域名最多开6个tcp连接,比如配置host127.0.0.1 liuk,通过浏览器访问liuk:8080/spring-tomcat/keepalive?sleep=10,同时十个窗口访问,发现最多创建了6个tcp连接
WX20200703-144810

根据服务端的输出发现,10次并发http请求,最多出现同时消费两个,原因是设置了tomcat最大线程数量

WX20200703-145017

http缓存

测试接口http://localhost:8080/spring-tomcat/cache/index.html

response header中和Cache相关的header为Cache-Control,如Cache-Control:max-age=10表示客户端缓存10s

服务端设置Cache-Control:max-age=5后,服务端的日志打印情况,无缓存的话正常应html/css一一对应,由于css进行了缓存,所以html访问多,而css访问少

Sat Jul 04 10:01:32 CST 2020cache html
Sat Jul 04 10:01:32 CST 2020cache css
Sat Jul 04 10:01:37 CST 2020cache html
Sat Jul 04 10:01:37 CST 2020cache css
Sat Jul 04 10:01:37 CST 2020cache html
Sat Jul 04 10:01:39 CST 2020cache html
Sat Jul 04 10:01:45 CST 2020cache html
Sat Jul 04 10:01:45 CST 2020cache css

Command + Shift +R 的“强制刷新”其实是发了一个request header “Cache-Control: no-cache”的请求

chunked传输

GET /spring-tomcat/trunked HTTP/1.1
Host: localhost:8080

HTTP/1.1 200
Transfer-Encoding: chunked
Date: Sat, 04 Jul 2020 06:24:12 GMT

6
test:0
6
test:1
6
test:2
6
test:3
6
test:4
6
test:5
6
test:6
6
test:7
6
test:8
6
test:9
0

https协议

课后思考

假如存在一个nginx 根据域名www.test.com配置转发到服务器s1,如果在地址栏输入ip而非域名,如何保证nginx代理成功?

  • [附1]
@Component
public class WebServerConfiguration implements WebServerFactoryCustomizer<ConfigurableWebServerFactory> {

    @Override
    public void customize(ConfigurableWebServerFactory factory) {
        //使用工厂类定制tomcat connector
        ((ConfigurableTomcatWebServerFactory) factory).addConnectorCustomizers(new TomcatConnectorCustomizer() {
            @Override
            public void customize(Connector connector) {
                Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
                // tcp 下述某个条件满足后 tcp连接即会断开
                //上次http请求后,10s无新的http请求,则断开http连接
                protocol.setKeepAliveTimeout(10000);
                //设置最大10000次请求后则断开keepalive
                protocol.setMaxKeepAliveRequests(10);
                //网络连接超时时间
                protocol.setConnectionTimeout(5000);
            }
        });
    }
}