问题
- 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的形式记录状态
response set到客户端保存的coolie数据,在客户请求时,会将所有的cookie上传至服务器
http报文结构
- 请求报文
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"}
- 响应报文
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接口多次,发现使用同一连接
- postman connection为close 请求api接口多次,发现每次请求都需要重新创建tcp连接
浏览器连接
需要注意的是一个浏览器可以对同一域名最多开6个tcp连接,比如配置host127.0.0.1 liuk
,通过浏览器访问liuk:8080/spring-tomcat/keepalive?sleep=10
,同时十个窗口访问,发现最多创建了6个tcp连接
根据服务端的输出发现,10次并发http请求,最多出现同时消费两个,原因是设置了tomcat最大线程数量
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);
}
});
}
}