推荐一款非常不错的 HTTP 请求发包工具: forest。

介绍

Java 日常开发中,肯定会经常遇到 HTTP 远程调用的情况,微服务场景下,有 feign/open-feign 这样的非常简洁的第三方方案。

但是在调用第三方服务的情况下,一般会选择 Apache 的 HttpClient、OkHttp 这样的第三方库 或者 JDK11 提供的 java.net.http.HttpClient;但是这些库都需要写不少代码,使用比较繁琐。

今天要推荐的 forest 用起来和 feign 非常类似, 最直观的感受如下:

架构

forest 的架构图如下(图片来自官网):

常用的http请求方式(第三方HTTP接口请求利器)(1)

forest架构图

可以将 forest 和 JDBC 类比:

声明式接口简单示例

这里就以 spring-boot 项目为例来简单演示 forest 的用法。

<dependency> <groupId>com.dtflys.forest</groupId> <artifactId>forest-Spring-boot-starter</artifactId> <version>1.5.25</version> </dependency>

// 1.5.1以后版本可以跳过此步,不需要 @ForestScan 注解来指定扫描的包范围 @ForestScan(basePackages = "com.example.demo.forestdemo.client") @SpringBootApplication public class ForestDemoApplication { public static void main(String[] args) { SpringApplication.run(ForestDemoApplication.class, args); } }

public interface HttpCallService { @Get("https://github.com/dromara/forest") String helloForest(); @Get("https://ditu.amap.com/service/regeo?longitude={0}&latitude={1}") Map<String, Object> getLocation(String longitude, String latitude); }

然后就可以直接调用接口了,不需要写实现。

@SpringBootTest class HttpCallServiceTest { @Autowired private HttpCallService httpCallService; @Test void helloForest() { final String response = httpCallService.helloForest(); System.out.println(response); } @Test void getLocation() throws JsonProcessingException { final Map<String, Object> location = this.httpCallService.getLocation("121.369", "31.258"); System.out.println(new ObjectMapper().writeValueAsString(location)); } }

编程式接口简单示例

如果你不想定义接口,就想直接发 HTTP 请求,forest 也提供了快捷接口:

class HttpCallServiceTest { @Test void shortcutMethodTest() { // get 请求 https://www.baidu.com // 然后将响应结果转为字符串 final String response = Forest.get("https://www.baidu.com").executeAsString(); System.out.println(response); } }

说个题外话: 个人感觉,在快捷接口(编程式接口)方面,还是 JDK11 提供的 java.net.http.HttpClient 的功能更加丰富,下面是 JDK11 的 HttpClient 实现的和上面例子一样的功能的写法:

public class MainTest { static final executorService EXECUTOR = Executors.newFixedThreadPool(16); @Test public void testGet() throws IOException, InterruptedException, URISyntaxException { final HttpClient httpClient = HttpClient .newBuilder() .executor(EXECUTOR) .build(); final Httprequest httpRequest = HttpRequest.newBuilder() .uri(new URI("https://www.baidu.com")) .header("User-Agent", "jdk 9 http client") .GET() .build(); final HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); System.out.println(httpResponse.statusCode()); System.out.println(httpResponse.body()); } @Test public void testAsyncGet() throws URISyntaxException { final HttpClient httpClient = HttpClient .newBuilder() .executor(EXECUTOR) .build(); final HttpRequest request = HttpRequest.newBuilder() .uri(new URI("https://www.baidu.com")) .GET() .build(); final CompletableFuture<HttpResponse<String>> response = httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()); response.whenComplete((resp, t) -> { if (t != null) { t.printStackTrace(); } else { System.out.println(resp.body()); System.out.println(resp.statusCode()); } }).join(); } }

个人感觉 forest 的声明式接口这点是非常简洁易用的。

其他各种特性建议直接看官方文档: https://forest.dtflyx.com/

,