Java 11 HTTP Client库的使用

这篇具有很好参考价值的文章主要介绍了Java 11 HTTP Client库的使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

每种编程语言里最常用的库恐怕是Http请求库了,如python里的requests包,nodejs里的request模块。
在Java世界里,也是百花齐放,山头林立。常用的有:

  • HttpURLConnection: 最早的JDK提供的类
  • Java 11提供的HttpClient
  • Apache HttpComponents项目中的HTTPClient
  • Square提供的OkHttpClient
  • Spring 自带的WebClient

本文着重介绍JDK 11的HttpClient。

Apache HttpComponents

该组件提供了两个核心类:

  • HttpCore: 更底层的传输处理类
  • HttpClient:基于HttpCore实现的HTTP-compliant 处理类

JDK 11 HTTP Client使用举例

JDK 11开始新增了HttpClient这个组件,方便我们发送同步或异步的http请求。

Post同步的json数据

public void invokePost() {
  
  try {
   String requestBody = prepareRequest();
   HttpClient client = HttpClient.newHttpClient();
   HttpRequest request = HttpRequest
     .newBuilder()
     .uri(URI.create("https://reqbin.com/echo/post/json"))
     .POST(HttpRequest.BodyPublishers.ofString(requestBody))
     .header("Accept", "application/json")
     .build();

   HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

   System.out.println(response.body());
  } catch (IOException | InterruptedException e) {
   e.printStackTrace();
  }
 }

 private String prepareRequest() throws JsonProcessingException {
  var values = new HashMap<String, String>() {
   {
    put("Id", "12345");
    put("Customer", "Roger Moose");
    put("Quantity", "3");
    put("Price","167.35");
   }
  };

  var objectMapper = new ObjectMapper();
  String requestBody = objectMapper.writeValueAsString(values);
  return requestBody;
 }

发送异步请求

用于同时发送大量的Http请求的场景,例如爬虫:

public void invoke() throws URISyntaxException {
  
  HttpClient client = HttpClient.newBuilder()
      .version(Version.HTTP_2)
      .followRedirects(Redirect.NORMAL)
      .build();
  
  HttpRequest request = HttpRequest.newBuilder()
     .uri(new URI(URLConstants.URL))
     .GET()
     .header(URLConstants.API_KEY_NAME, URLConstants.API_KEY_VALUE)
     .timeout(Duration.ofSeconds(10))
     .build();
  
  
  client.sendAsync(request, BodyHandlers.ofString())
    .thenApply(HttpResponse::body)
    .thenAccept(System.out::println)
    .join();
 }

会话保持

//使用默认的CookieManager,并且接受所有第三方Cookie
cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
httpClient = HttpClient.newBuilder()
        .connectTimeout(Duration.ofMillis(5000))
        .cookieHandler(cookieManager)//注意在此步骤送送入
        .followRedirects(HttpClient.Redirect.NORMAL)
        .build();

爬虫示例:HttpClient 并发编程

HttpClient uses executor java.util.concurrent.Executors.newCachedThreadPool().

private static final ExecutorService executorService = Executors.newFixedThreadPool(5);

private static final HttpClient httpClient = HttpClient.newBuilder()
            .executor(executorService)
            .version(HttpClient.Version.HTTP_2)
            .connectTimeout(Duration.ofSeconds(10))
            .build();

    public static void main(String[] args) throws Exception {

        List<URI> targets = Arrays.asList(
                new URI("https://httpbin.org/get?name=mkyong1"),
                new URI("https://httpbin.org/get?name=mkyong2"),
                new URI("https://httpbin.org/get?name=mkyong3"));

        List<CompletableFuture<String>> result = targets.stream()
                .map(url -> httpClient.sendAsync(
                        HttpRequest.newBuilder(url)
                                .GET()
                                .setHeader("User-Agent", "Java 11 HttpClient Bot")
                                .build(),
                        HttpResponse.BodyHandlers.ofString())
                        .thenApply(response -> response.body()))
                .collect(Collectors.toList());

        for (CompletableFuture<String> future : result) {
            System.out.println(future.get());
        }

    }

发送multipart/form-data数据

遗憾的是,JDK 11 HttpClient对这类数据支持不太友好。

private val httpClient: HttpClient = HttpClient.newHttpClient()

fun main() {
    val file = File(
        LocalTest::class.java.classLoader.getResource("my_pic_from_resources.jpg").file
    )
    val token = "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"

    val data: MutableMap<String, Any> = LinkedHashMap()
    data["chat_id"] = "123456789"
    data["photo"] = file
    val boundary: String = BigInteger(35, Random()).toString()

    val request = HttpRequest.newBuilder()
        .uri(URI.create("https://api.telegram.org/bot$token/sendPhoto"))
        .postMultipartFormData(boundary, data)
        .build()

    val response = httpClient.send(request, HttpResponse.BodyHandlers.ofString())
    println(response)
}

fun HttpRequest.Builder.postMultipartFormData(boundary: String, data: Map<String, Any>): HttpRequest.Builder {
    val byteArrays = ArrayList<ByteArray>()
    val separator = "--$boundary\r\nContent-Disposition: form-data; name=".toByteArray(StandardCharsets.UTF_8)

    for (entry in data.entries) {
        byteArrays.add(separator)
        when(entry.value) {
            is File -> {
                val file = entry.value as File
                val path = Path.of(file.toURI())
                val mimeType = Files.probeContentType(path)
                byteArrays.add("\"${entry.key}\"; filename=\"${path.fileName}\"\r\nContent-Type: $mimeType\r\n\r\n".toByteArray(StandardCharsets.UTF_8))
                byteArrays.add(Files.readAllBytes(path))
                byteArrays.add("\r\n".toByteArray(StandardCharsets.UTF_8))
            }
            else -> byteArrays.add("\"${entry.key}\"\r\n\r\n${entry.value}\r\n".toByteArray(StandardCharsets.UTF_8))
        }
    }
    byteArrays.add("--$boundary--".toByteArray(StandardCharsets.UTF_8))

    this.header("Content-Type", "multipart/form-data;boundary=$boundary")
        .POST(HttpRequest.BodyPublishers.ofByteArrays(byteArrays))
    return this
}

或者,借用Apache Http组件的部分类:

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.channels.Channels;
import java.nio.channels.Pipe;
import java.nio.charset.StandardCharsets;

import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.StringBody;

public class MultipartRequest {

    public static void main(String[] args) throws Exception {

        /**
        * Create a Multipart request body with MultipartEntityBuilder.
        */
        HttpEntity httpEntity = MultipartEntityBuilder.create()
                // FORM
                .addPart("name",
                        new StringBody("<Spring Cloud>",
                                ContentType.create("application/x-www-form-urlencoded", StandardCharsets.UTF_8)))
                // JSON
                .addPart("info",
                        new StringBody("{\"site\": \"https://www.springcloud.io\"}", ContentType.APPLICATION_JSON))
                // FILE
                .addBinaryBody("logo", new File("C:\\Users\\KevinBlandy\\Desktop\\logo.png"), ContentType.IMAGE_PNG,
                        "logo.png")
                .build();

        /**
        * Use pipeline streams to write the encoded data directly to the network
        * instead of caching it in memory. Because Multipart request bodies contain
        * files, they can cause memory overflows if cached in memory.
        */
        Pipe pipe = Pipe.open();

        // Pipeline streams must be used in a multi-threaded environment. Using one
        // thread for simultaneous reads and writes can lead to deadlocks.
        new Thread(() -> {
            try (OutputStream outputStream = Channels.newOutputStream(pipe.sink())) {
                // Write the encoded data to the pipeline.
                httpEntity.writeTo(outputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }

        }).start();

        HttpClient httpClient = HttpClient.newHttpClient();

        HttpRequest request = HttpRequest.newBuilder(new URI("http://localhost/upload"))
                // The Content-Type header is important, don't forget to set it.
                .header("Content-Type", httpEntity.getContentType().getValue())
                // Reads data from a pipeline stream.
                .POST(BodyPublishers.ofInputStream(() -> Channels.newInputStream(pipe.source()))).build();

        HttpResponse<String> responseBody = httpClient.send(request, BodyHandlers.ofString(StandardCharsets.UTF_8));

        System.out.println(responseBody.body());
    }
}

如果不想引入上面的Apache Http组件,则自己写一个类MultipartFormDataBodyPublisher也行。然后如下使用:

var body = new MultipartFormData()
            .add(StringPart("name", "Hello,")
            .add(StringPart("value", "World!")
            .addFile("f", Path.of("index.html"), "text/html")
            .addFile("cpuinfo", Path.of("/proc/cpuinfo"), "text/html");

var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("http://localhost:8080/"))
    .header("Content-Type", body.contentType())
    .POST(body)
    .build();
var response = client.send(request, BodyHandlers.ofLines());
response.body().forEach(line -> System.out.println(line));

其它HTTP Client包装库

methanol

A Lightweight HTTP extensions for Java

cVurl

cVurl is an open-source wrapper for the Java HTTP client. It is written in Java 11 and can be used with any JDK 11.0.2 or newer.

public void cVurl() {
    CVurl cVurl = new CVurl();

    //POST
    Result result = cVurl.post("https://api.imgflip.com/caption_image")
        .queryParams(Map.of(
                "template_id", "112126428",
        "username", "test-user",
        "password", "123test321",
        "text0", "text0",
        "text1", "text1"
        ))
        .asObject(Result.class);

    System.out.println("CVurl POST: " + result);
}

它支持Compression、Multipart、Form data这些Java 11 HttpClient不具备的特性。

Avaje-HTTP

  • Fluid API for building URLs and payload
  • JSON marshaling using Avaje Jsonb/Jackson/Gson
  • Light Feign-style interfaces via annotation processing.
  • Request/Response Interception
  • Authorization via Basic Auth or OAuth Bearer Tokens
  • Async and sync API

个人建议

在实际项目中,设计符合自身项目需求的HTTP client接口,并基于JDK 11 HTTP client实现,独立于任何上述库。文章来源地址https://www.toymoban.com/news/detail-706802.html

参考链接

  • comparison-of-java-http-clients
  • A closer look at the Java 11 HTTP Client
  • cvurl
  • methanol
  • avaje-http
  • java.net.HttpClient multipart/form-data BodyPublisher

到了这里,关于Java 11 HTTP Client库的使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • How to disable certificate validations in the Java HTTP Client

    Java 11 introduced the HTTP Client, an API that made it easier to send HTTP requests with vanilla Java. By default, it throws an exception if there are certificate path or hostname verification errors in the request. Let’s see how to bypass certificate validations for cases where this is really necessary. To ignore both certificate path and hostname verif

    2024年01月19日
    浏览(44)
  • 成功解决:java.lang.NoSuchMethodError: reactor.netty.http.client.HttpClient.chunkedTransfer(Z)Lreactor/ne

    前言 在微服务中整合gateway网关,网关服务成功启动、在访问地址的时候报错。主要原因是依赖父工程 spring-boot-starter-parent 的版本和依赖网关 spring-cloud-starter-gateway 的版本不同导致。 在进行地址跳转的时候,没有做出相应的页面跳转。同时控制台报错 先前的版本(错误版本

    2024年02月16日
    浏览(96)
  • 用Java开发HTTP代理服务器

    HTTP代理服务器是一种网络应用,它充当位于客户端和目标服务器之间的中间节点,将客户端发出的HTTP请求转发给目标服务器,并将目标服务器返回的HTTP响应内容回传给客户端。通过使用代理服务器,客户端可以避免直接访问目标服务器,从而更加安全地访问互联网资源。

    2024年02月16日
    浏览(55)
  • JAVA使用HTTP代理

    在Java中使用HTTP代理,可以通过设置系统属性来实现。具体步骤如下: 1. 创建一个代理对象 ```java Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\\\"代理服务器地址\\\", 代理服务器端口)); ``` 2. 设置系统属性 ```java System.setProperty(\\\"http.proxyHost\\\", \\\"代理服务器地址\\\"); System.setProperty(\\\"h

    2024年02月15日
    浏览(28)
  • 使用Java调用http接口

    使用Java调用HTTP接口的步骤如下: 创建一个URL对象,指定HTTP接口的地址。 打开URL连接,获取URLConnection对象。 设置URLConnection对象的请求方式、超时时间等参数。 发送请求,并获取服务器返回的响应结果。 处理响应结果,可以将响应结果转换成字符串或其他格式。 下面是一

    2024年02月15日
    浏览(42)
  • 如何使用idea的http client完成全局变量的缓存

    response.body的示例值,具体根据业务而定 登入并将token保存到全局变量中方中 使用全局变量的值

    2024年02月15日
    浏览(32)
  • 使用Java实现HTTP GET请求

    HTTP GET请求是互联网上最常见的请求类型之一,用于从指定的资源获取数据。在Java中,有多种方法可以实现HTTP GET请求,包括使用Java的内置类库 java.net.HttpURLConnection ,或者使用更高级的第三方库如Apache HttpClient和OkHttp。 下面,我们将详细讨论如何使用Java的内置类库实现HTTP

    2024年03月22日
    浏览(45)
  • java创建上传文件接口并使用HTTP测试

    备注: 使用jersey框架 2.1.1.上传本地文件 参考链接: Jersey (JAX-RS) multiple files upload example

    2024年02月11日
    浏览(286)
  • Flutter如何使用mvi? bloc结合自定义http库的实现

    提示:本篇并不算严谨的科普文章,仅仅只是记录使用bloc的思路 最近对kotlin的mvi使用比较娴熟,但是关于flutter架构相关的比较少,之前也有看过provider这些框架总觉得没那么好使而且还挺麻烦的,现在也有大佬研究getx的mvvm,这里我就不展开了,我的本意是想使用getx作为路

    2024年02月11日
    浏览(38)
  • Java21对虚拟线程进行http压测使用不同的GC

    JDK21默认GC是G1. JDK21除了G1外,还可以使用ZGC(Java11预览、Java15正式版),Java21在ZGC基础上继续推出了分代ZGC,目前还是试行阶段。 开启ZGC: java -XX:+UseZGC -jar myapp.jar 开启ZGC,并试用分代ZGC java -XX:+UseZGC -XX:+ZGenerational -jar myapp.jar 以下的对一个启用tomcat虚拟线程的spring boot 项目

    2024年02月05日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包