龙空技术网

SpringCloud OpenFeign 使用 okhttp 发送 HTTP 请求与 HTTP/2 探索

暖杯巧克力aya 120

前言:

现在我们对“java启动服务后http怎么调用”可能比较看重,同学们都需要剖析一些“java启动服务后http怎么调用”的相关内容。那么小编同时在网上网罗了一些关于“java启动服务后http怎么调用””的相关资讯,希望我们能喜欢,各位老铁们快快来了解一下吧!

背景

SpringCloud OpenFeign 支持3种 HTTP client 来发送请求,分别是:

HttpURLConnection 默认形式,Java提供。Apache HttpClient 5okhttp

我们使用的 HttpURLConnection 即默认形式,预期提升请求时效,结合推荐,替换成 okhttp 测试效果。

okhttp 介绍

okhttp 有如下特性优势:

支持 HTTP/2使用 HTTP 连接池 (HTTP/2 不可用)使用GZIP 压缩对响应缓存连接恢复,如果访问的服务有多个地址,那么连接一个地址失败后,重试其他地址

我们可使用到的特性是 HTTP 连接池和连接恢复。

实现

代码设置

1.在 pom.xml 文件中引入 okhttp 的包。

<dependency>		<groupId>io.github.openfeign</groupId>		<artifactId>feign-okhttp</artifactId>	</dependency>

2.在 Spring 的配置文件中,设置开启 okhttp

feign:  okhttp:    enabled: true

测试验证

调试 Feign 请求的代码,可以看到请求发送已经使用了 okhttp。

性能比较

对一个请求,其中实现中包含对另一个服务接口的 Feign 调用,进行 ab 压测,使用100个并发,发送10000次请求,比较其耗时。

1. HttpURLConnection 耗时情况

2. okhttp 耗时情况

可以看到请求时效的提升。

遇到的问题

1. method GET must not have a request body

Caused by: java.lang.IllegalArgumentException: method GET must not have a request body.	at okhttp3.Request$Builder.method(Request.kt:258)

是因为 okhttp 框架要求 GET 请求不能有 requestbody 。当方法设置 `@RequestMapping` 而未设置 method 时,使用 GET 请求。

修改方案:1. POST 方法时,在 @RequestMapping 上设置 method 参数。2. GET 方法时,参数使用 @RequestParam 而不是 @RequestBody。

okhttp 关于 GET 请求是否支持 requestbody ,可在 github issue 区查看讨论。

2. jar 包版本冲突报错

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [okhttp3.OkHttpClient$Builder]: Factory method 'okHttpClientBuilder' threw exception; nested exception is java.lang.NoSuchFieldError: Companion	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653)	... 111 common frames omittedCaused by: java.lang.NoSuchFieldError: Companion	at okhttp3.internal.Util.<clinit>(Util.kt:70)	at okhttp3.internal.concurrent.TaskRunner.<clinit>(TaskRunner.kt:309)	at okhttp3.ConnectionPool.<init>(ConnectionPool.kt:41)	at okhttp3.ConnectionPool.<init>(ConnectionPool.kt:47)

是因为有其他 jar 包引入了 okhttp ,版本不同,底层实现的方法有不同。通过 IDE 查看各依赖。

修改方案:因为其他 jar 包引入的 okhttp 版本较低,升级高版本不可用。该服务采用不开启 okhttp,修改服务的 pom 文件不引入 okhttp 包。因为我们是基础的通用依赖,使用 exclusion 排除。

<exclusions>	<exclusion>		<groupId>io.github.openfeign</groupId>		<artifactId>feign-okhttp</artifactId>	</exclusion></exclusions>
Feign 请求开启 HTTP/2 探索

okhttp 支持 HTTP/2,那么我们使用 HTTP/2 有什么好处呢?在 HTTP/2 中,当客户端请求数据时,服务器会一次性将多个数据流发送到客户端,而不是逐个依次发送,这种数据传输方法成为多路复用。同一个主机的所有请求共用一个 socket 连接。

HTTP/2 的类型

1.h2 (HTTP/2 over TLS)

2.h2c (HTTP/2 over TCP)

h2 必须要开启 SSL,也就是基于 HTTPS。而 h2c 可以不开启 SSL。

server 端开启 HTTP/2

Spring 对 h2 和 h2c 都支持。开启 HTTP/2 通过配置文件开关即可。添加如下配置:

server:  http2:    enabled: true

服务启动后,发送请求查看到,验证服务端开启了 HTTP/2 。

`curl -I --http2 localhost:8885/***`

Feign请求的客户端开启 HTTP/2

1.okhttp 支持 HTTP/2,但是只支持 h2 的形式。目前我们项目并未引入 SSL,所以不可行。框架也无支持 h2c 的计划,相关讨论在github issue 区。

2.HttpURLConnection 在 HTTP/2 协议全面改动后,这个类无法升级支持。Java 是提供了一套新的类来支持 HTTP/2,它们是 HttpClient。而 OpenFeign 的接入还在 snapshot 版本,SpringCloud 接入还需要等待。

GitHub github = Feign.builder()                     .client(new Http2Client())                     .target(GitHub.class, ";);

<parent>    <groupId>io.github.openfeign</groupId>    <artifactId>parent</artifactId>    <version>12.2-SNAPSHOT</version>  </parent>

3.Apache HttpClient 5 启用该 http client 后,打开 Spring 的 HTTP/2 开关,发起请求并不是 HTTP/2 的形式,h2c 形式未成功。

如上 SpringCloud OpenFeign 开启 HTTP/2 均未成功,打算等 OpenFeign 12.2发布后再测试。

标签: #java启动服务后http怎么调用