java8中okHttp发送http2请求
转载:https://blog.csdn.net/guzhipeng/article/details/125218701
问题背景:
最近想用springboot2.0搭建支持http2.0的服务器。搭好了之后,通过Chrome访问,显示http协议版本为h2(服务器升级成功,证书配置成功)。
现在想自己写个客户端进行测试。百度了一下okhttp3可以支持http2.0,配好了公钥之后,接口是可以发通了,但是看了下response用的protocol还是http1.1版本。
后台代码:
1.springboot配置:
2.EchoController:(只是简单的返回一个ECHO字符串)
3.客户端测试:
public class EchoTest {
private static String url = "https://localhost:8080/echo";
private static OkHttpClient client;
// build request
Request request = new Request.Builder()
.url(url)
.build();
// send request
Response response = client.newCall(request).execute();
// print message
String rslt = response.body().string();
String protocol = response.protocol().name();
System.out.println(rslt); // 打印响应:ECHO
System.out.println(protocol); // 打印http protocol
}
@BeforeClass
public static void initClient() throws Exception {
// 导入公钥证书
KeyStore keyStore = KeyStore.getInstance("JKS"); // .jks格式
Resource resource = new ClassPathResource("secret/mytruststore.jks");
keyStore.load(resource.getInputStream(), "line1983".toCharArray());
// 初始化证书管理factory
TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
factory.init(keyStore);
// 获得X509TrustManager
TrustManager[] trustManagers = factory.getTrustManagers();
X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
// 初始化sslContext
SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); // 这里选择的是tls1.2版本
sslContext.init(null, new TrustManager[] { trustManager }, null);
// 获得sslSocketFactory
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
// 初始化client builder
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory, trustManager)
.hostnameVerifier(new HostnameVerifier() { // 放过host验证
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
// build client
client = builder.build();
}
}
运行测试:
response:
Response{protocol=http/1.1, code=200, message=OK, url=https://localhost:8080/echo}
百度了一篇文章,尝试在build request的时候,对头部进行一些修改:
客户端在请求头部中指定Connection和Upgrade两个字段发起 HTTP/1.1 协议升级. HTTP/2 的协议名称是 h2c, 代表 HTTP/2 ClearText.
// build request
Request request = new Request.Builder()
.url(url)
.addHeader("Connection", "Upgrade, HTTP2-Settings")
.addHeader("Upgrade", "h2c")
.build();
但结果还是一样:
ECHO!!
HTTP_1_1
之前有按照@Feng_Yu评论的StackOverflow上的思路去尝试在build okHttpClient的时候,指定h2协议,
// 初始化client builder
OkHttpClient.Builder builder = new OkHttpClient.Builder();
List<Protocol> protocols = new ArrayList<>();
protocols.add(Protocol.HTTP_1_1); // 这里如果,只指定h2的话会抛异常
protocols.add(Protocol.HTTP_2); // 这里如果,只指定h2的话会抛异常
builder.sslSocketFactory(sslSocketFactory, trustManager)
.protocols(protocols) // 设置builder protocols
.hostnameVerifier(new HostnameVerifier() { // 放过host验证
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
最后发现还是一样,能收到正确的响应,但是协议还是http1.1。后面在debug的时候发现使用默认方法对client进行build的时候,就已经选择了h2协议了。
搞不定,有会弄的大神麻烦指教一下。。。请他冰嚯阔落。。
各路大神提点建议也都行!
回答
https://stackoverflow.com/que...
jdk1.7,1.8 原生不支持http2.0,okhttp可以发2.0的请求,你的代码改后是没问题的,但需要引入alpn-boot jar包配合才能模拟http2.0