HTTP2.0特性
通俗易懂篇:https://www.cnblogs.com/yingsmirk/p/5248506.html
深入了解篇:https://www.jianshu.com/p/67c541a421f9
HTTP/2連接是建立在TCP連接之上的應用層協議,客戶端是TCP連接的發起者。
HTTP/2使用和HTTP/1.1一樣的 URI schemes:"http" 和 "https",並且還是共享同樣的默認端口:http的80,https的443。這意味着,對於"http" 和 "https"確定其是否支持HTTP/2協議的方式是不同的。
在官方文檔中,為HTTP/2協議定義了兩個版本:h2 和 h2c:
h2版本的協議是建立在TLS層之上的HTTP/2協議,這個標志被用在TLS應用層協議協商(TLS-ALPN)域和任何其它的TLS之上的HTTP/2協議。
h2c版本是建立在明文的TCP之上的HTTP/2協議,這個標志被用在HTTP/1.1的升級協議頭域和其它任何直接在TCP層之上的HTTP/2協議。
搭建帶有證書的h服務端:https://
要使用HTTP/2需要注意以下幾點
1.雖然HTTP/2沒有明確要求必須使用TLS,但當前幾乎所有瀏覽器均只支持 HTTP/2 Over TLS。所以在使用之前我們需要先制作一張證書。
2.如果您的項目中用的是tomcat或jetty,它們並不能直接支持HTTP/2,但是undertow可以。具體可以參考Spring Boot的文檔:https://docs.spring.io/spring-boot/docs/2.0.5.RELEASE/reference/htmlsingle/#howto-configure-http2
3.我們制作的證書是不被瀏覽器認可的,所以會有安全提示,不能用於生產環境。
在本文的例子中使用的是undertow。
1.制作證書:
使用JDK自帶的keytool,證書類型為:PKCS12
打開cmd 輸入下面的命令:
keytool -genkey -alias undertow -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -dname "CN=localhost, OU=localhost, O=localhost, L=hangzhou, ST=zhejiang, C=CN"
輸入密鑰庫口令:
再次輸入新口令:
執行時會要求輸入證書口令,這里輸入的是123456。執行完命令后會在執行的文件夾生成一個keystore.p12的文件。
keytool
-genkey
-alias undertow (別名)
-storetype PKCS12 (證書類型)
-keyalg RSA (算法)
-keysize 2048 (秘鑰長度)
-keystore keystore.p12 (指定生成證書的位置和證書名稱)
-dname "
CN=localhost,(姓名姓氏)
OU=localhost,(組織單位)
O=localhost,(組織名稱)
L=hangzhou,(所在城市或者區域名稱)
ST=zhejiang,(所在的省/市/自治區名稱)
C=CN"(該單位的雙字母國家/地區代碼)
keytool的詳細用法:
https://docs.oracle.com/javase/8/docs/technotes/tools/windows/keytool.html
常見的證書格式及其說明參考:
http://www.cnblogs.com/xq1314/archive/2017/12/05/7987216.html
配置Web容器
spring boot默認使用的是tomcat,我們需要先將tomcat移除,然后換成undertow。
在搭建好的springboot項目中引入 注意springboot在2.0版本才開始支持http2,springboot2.0 支持的jdk最低版本為java8
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
如果不移除tomcat依賴會一直以Tomcat作為容器啟動。
然后將剛才生成的keystore.p12拷貝到src/main/resources下。
然后在application.properties中配置服務器信息。
#端口號
server.port=8443
#ip地址
server.address=0.0.0.0
#啟用HTTP響應壓縮
server.compression.enabled=true
# 啟用http2
server.http2.enabled=true
# 啟用ssl
server.ssl.enabled=true
#證書位置
server.ssl.key-store=classpath:keystore.p12
# 證書密碼
server.ssl.key-store-password=123456
# 證書類型
server.ssl.key-store-type= PKCS12
# 協議類型
server.ssl.protocol=TLSv1.2
server.ssl.key-alias=undertow
這時如果啟動服務器,是只支持https的。
@SpringBootApplication
public class DemoApplication implements WebServerFactoryCustomizer<UndertowServletWebServerFactory>{
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void customize(UndertowServletWebServerFactory undertowServletWebServerFactory) {
undertowServletWebServerFactory.addBuilderCustomizers(new UndertowBuilderCustomizer() {
@Override
public void customize(Undertow.Builder builder) {
builder.addHttpListener(8080, "0.0.0.0");
}
});
}
}
這里增加8080端口的監聽,配置參考:
https://docs.spring.io/spring-boot/docs/2.0.5.RELEASE/reference/htmlsingle/#howto-configure-webserver
https://docs.spring.io/spring-boot/docs/2.0.5.RELEASE/reference/htmlsingle/#howto-enable-multiple-listeners-in-undertow
啟動后可以看到控制台打印出如下信息:
測試
增加一個測試控制器
瀏覽器訪問:https://192.168.110.117:8443/someData
觀察兩次請求的size,一次是92一次是70,這是因為HTTP/2的頭部壓縮技術。
瀏覽器訪問:http://localhost:8080/someData HTTP/1.1協議 而且數據包要比HTTP/2的數據包大,並且無論刷新多少次,大小是不變的。
搭建h2c服務端:http://
從Spring boot 2.0的官方文檔上看,明確寫明了“Spring boot 不支持h2c —— HTTP/2協議的明文版本”,於是就想其它辦法來支持h2c。
首先,想的是通過外置的tomcat配置來支持h2c,因為tomcat8.5中的server.xml配置中,有HTTP/2協議相關的配置:
這里顯示要添加證書,明顯支持的是基於TLS層之上的h2版本的HTTP/2協議,但是從配置上可以禁用SSL,於是就嘗試了一下,果然成功了。配置成如下示例,就支持h2c了:
<Connector port="5080" protocol="HTTP/1.1" connectionTimeout="20000">
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" /></Connector>
tomcat容器自身是支持多個connector的配置的,查看springboot2.0是否支持同時配置多個Connector
文檔中示例是通過 java configure 的方式配置一個https的connector,在application.properties中不支持配置多個connector。
因此模仿這外置tomcat配置h2c的方式,在Spring boot 2.0 的內置tomcat中通過java configure的方式配置h2c協議,具體代碼如下:
新建一個springboot項目,加入以下配置即可
/
**
* h2c協議
* @return
*/
@Bean
public ServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
tomcat.addAdditionalTomcatConnectors(createH2cConnector());
return tomcat;
}
private Connector createH2cConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
Http2Protocol upgradeProtocol = new Http2Protocol();
connector.addUpgradeProtocol(upgradeProtocol);
//connector.setScheme("http");
connector.setPort(5080);
return connector;
}
這時啟動我們的Spring boot應用,會發現最后的啟動日志有兩個端口
因為瀏覽器只支持h2 所以使用curl 驗證h2c的服務端 或者用wireshark抓包查看
檢查你的curl是否支持http2
從上面的 Features 信息發現,我的curl工具是支持HTTP/2協議的。
下面開始驗證我Spring boot 的服務在5080端口是否是h2c,具體如下:
輸入curl -v --http2 "http://192.168.110.117:5080/someData"
從結果看 已經驗證通過。