async-http-client使用示例

server/2025/2/8 11:03:53/

文章目录

    • 概要
    • 整体架构流程
    • 技术名词解释
    • 技术细节
    • 小结

概要

async-http-client是一个用于 Java 平台的高性能、非阻塞 HTTP 客户端库,它允许开发者以异步的方式发送 HTTP 请求并处理响应,从而提高应用程序的性能和响应性。

主要特点

  1. 异步处理:基于 Netty 框架实现,支持异步发送 HTTP 请求和处理响应,避免了传统同步请求中的阻塞。

  2. 支持多种请求方法:支持 GET、POST、PUT、DELETE 等常见的 HTTP 请求方法。

  3. 灵活的配置:通过 AsyncHttpClientConfig 类可以配置连接池、超时时间、代理服务器等。

  4. 多种响应处理方式:支持通过回调函数、FutureCompletableFuture 来处理异步响应。

项目准备

首先创建一个maven工程,引入一下依赖:

<dependency>

<groupId>commons-io</groupId>

<artifactId>commons-io</artifactId>

<version>1.3</version>

</dependency>

<dependency>

<groupId>com.ning</groupId>

<artifactId>async-http-client</artifactId>

<version>1.9.40</version>

</dependency>

技术细节

创建一个工具类:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.zip.GZIPInputStream;public class EncodingUtil {/*** @param str* @param newCharset* @return* @throws UnsupportedEncodingException*/public static String changeCharset(String str, String newCharset)throws UnsupportedEncodingException {if (str != null) {// 用默认字符编码解码字符串。byte[] bs = str.getBytes(Charset.defaultCharset());// 用新的字符编码生成字符串return new String(bs, newCharset);}return null;}/*** @param str* @param oldCharset* @param newCharset* @return* @throws UnsupportedEncodingException*/public static String changeCharset(String str, String oldCharset,String newCharset) throws UnsupportedEncodingException {if (str != null) {// 用旧的字符编码解码字符串。解码可能会出现异常。byte[] bs = str.getBytes(oldCharset);// 用新的字符编码生成字符串return new String(bs, newCharset);}return null;}/*** @param bytes* @param oldCharset* @param newCharset* @return* @throws UnsupportedEncodingException*/public static byte[] changeCharset(byte[] bytes, String oldCharset,String newCharset) throws UnsupportedEncodingException {byte[] b = null;String s = null;if (bytes != null) {//增加判断返回报文的编码格式为gzip时进行解压缩if("gzip".equals(oldCharset)){b = unGZip(bytes);s = new String(b,"UTF-8");}else{s = new String(bytes, oldCharset);}// 用新的编码生成字节return s.getBytes(newCharset);}return null;}/*** @param bytes* @param newCharset* @return* @throws UnsupportedEncodingException*/public static byte[] changeCharset(byte[] bytes,String newCharset) throws UnsupportedEncodingException {if (bytes != null) {// 用缺省的编码解码字节。解码可能会出现异常。String s = new String(bytes,Charset.defaultCharset());// 用新的编码生成字节return s.getBytes(newCharset);}return null;}/*** @param str* @param stringCharset* @param newCharset* @return* @throws UnsupportedEncodingException*/public static byte[] convertByCharset(String str, String stringCharset,String newCharset) throws UnsupportedEncodingException {if (str != null) {String newString = changeCharset(str, stringCharset, newCharset);return newString.getBytes(newCharset);}return null;}/*** @param bytes* @param bytesCharset* @param newCharset* @return* @throws UnsupportedEncodingException*/public static String convertByCharset(byte[] bytes, String bytesCharset,String newCharset) throws UnsupportedEncodingException {if (bytes != null) {byte[] newBytes = changeCharset(bytes, bytesCharset, newCharset);return new String(newBytes, newCharset);}return null;}/*** 解压缩gzip格式数据* @param data* @return*/public static byte[] unGZip(byte[] data) {  byte[] b = null;  try {  ByteArrayInputStream bis = new ByteArrayInputStream(data);  GZIPInputStream gzip = new GZIPInputStream(bis);  byte[] buf = new byte[data.length];  int num = -1;  ByteArrayOutputStream baos = new ByteArrayOutputStream();  while ((num = gzip.read(buf, 0, buf.length)) != -1) {  baos.write(buf, 0, num);  }  b = baos.toByteArray();  baos.flush();  baos.close();  gzip.close();  bis.close();  } catch (Exception ex) {  ex.printStackTrace();  }  return b;  }
}

创建一个发送类:

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;import com.ning.http.client.AsyncCompletionHandler;
import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.AsyncHttpClient.BoundRequestBuilder;
import com.ning.http.client.AsyncHttpClientConfig;
import com.ning.http.client.Request;
import com.ning.http.client.AsyncHttpClientConfig.Builder;
import com.ning.http.client.providers.netty.NettyAsyncHttpProvider;public class AsyncHttpClientTest {public static final String COMMON_UTF8 = "utf-8";public static void request(String requestUrl,String body,String method) {//初始化客户端Builder builder = new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(true).setAllowPoolingSslConnections(true).setAcceptAnyCertificate(true);builder.setConnectTimeout(600000).setReadTimeout(660000).setRequestTimeout(660000).setMaxRequestRetry(0).setMaxConnections(500).setMaxConnectionsPerHost(500);AsyncHttpClientConfig aconfig = builder.build();AsyncHttpClient httpClient = new AsyncHttpClient(new NettyAsyncHttpProvider(aconfig), aconfig);//设置请求方式和编码String requestEncoding="gbk";String currentEncoding="gbk";BoundRequestBuilder requestBuilder = null;try {if (method.equalsIgnoreCase("GET")) {requestBuilder = httpClient.prepareGet(requestUrl);} else if (method.equalsIgnoreCase("POST")) {requestBuilder = httpClient.preparePost(requestUrl);byte[] requestBody = createBody(body, requestEncoding, currentEncoding);requestBuilder.setBody(requestBody);} else if (method.equalsIgnoreCase("PUT")) {requestBuilder = httpClient.preparePut(requestUrl);byte[] requestBody = createBody(body, requestEncoding, currentEncoding);requestBuilder.setBody(requestBody);} else if (method.equalsIgnoreCase("DELETE")) {requestBuilder = httpClient.prepareDelete(requestUrl);byte[] requestBody = createBody(body, requestEncoding, currentEncoding);requestBuilder.setBody(requestBody);}//设置请求头requestBuilder.addHeader("User-Agent", "PostmanRuntime/7.37.3");requestBuilder.addHeader("Accept", "*/*");requestBuilder.addHeader("Connection", "keep-alive");requestBuilder.addHeader("Cache-Control", "no-cache");requestBuilder.addHeader("Content-Encoding", requestEncoding);requestBuilder.addHeader("Content-Type", "text/html; charset="+requestEncoding);requestBuilder.addHeader("X-Gov-Signature", "4c22d25b44eb437f9c6358e927838a22");//发送请求Request request = requestBuilder.build();AsyncCompletionHandler completionHandler = new AsyncRequestResultHandler(httpClient, request, 3);httpClient.executeRequest(request, completionHandler);} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public static void main(String[] args) {//发送目标请求地址String requestUrl = "http://www.webxml.com.cn/WebServices/weatherwebService.asmx?wsdl";requestUrl="http://localhost:8081/sleepdemo/SleepServiet";requestUrl="http://192.168.17.15:10010/encoding/utf-8";requestUrl="http://192.168.17.15:10001/testencoding";String body="测试";try {BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("test.txt"),"GB2312"));String line;StringBuffer buffer=new StringBuffer();while ((line = reader.readLine()) != null) {buffer.append(line);}reader.close();body=buffer.toString();} catch (IOException e) {e.printStackTrace();}String method="POST";request(requestUrl,body,method);}/*** 创建消息体* @param body* @param requestEncoding* @param currentEncoding* @return* @throws UnsupportedEncodingException*/public static byte[] createBody(Object body, String requestEncoding, String currentEncoding)throws UnsupportedEncodingException {String oldEncoding = currentEncoding != null ? currentEncoding : COMMON_UTF8;try {if (body instanceof String) {if (requestEncoding.equalsIgnoreCase(oldEncoding)) {return ((String) body).getBytes(requestEncoding);} else {byte[] bytes = EncodingUtil.convertByCharset((String) body, oldEncoding, requestEncoding);return bytes;}} else if (body instanceof byte[]) {if (requestEncoding.equalsIgnoreCase(oldEncoding)) {return (byte[]) body;} else {byte[] bytes = EncodingUtil.changeCharset((byte[]) body, oldEncoding, requestEncoding);return bytes;}}} catch (UnsupportedEncodingException e) {e.printStackTrace();}return (byte[]) body;}public static String getUTF8StringFromGBKString(String gbkStr) {  try {  return new String(getUTF8BytesFromGBKString(gbkStr), "UTF-8");  } catch (UnsupportedEncodingException e) {  throw new InternalError();  }  }  public static byte[] getUTF8BytesFromGBKString(String gbkStr) {  int n = gbkStr.length();  byte[] utfBytes = new byte[3 * n];  int k = 0;  for (int i = 0; i < n; i++) {  int m = gbkStr.charAt(i);  if (m < 128 && m >= 0) {  utfBytes[k++] = (byte) m;  continue;  }  utfBytes[k++] = (byte) (0xe0 | (m >> 12));  utfBytes[k++] = (byte) (0x80 | ((m >> 6) & 0x3f));  utfBytes[k++] = (byte) (0x80 | (m & 0x3f));  }  if (k < utfBytes.length) {  byte[] tmp = new byte[k];  System.arraycopy(utfBytes, 0, tmp, 0, k);  return tmp;  }  return utfBytes;  }
}

这个是返回请求的接收:

import java.util.zip.GZIPInputStream;import org.apache.commons.io.IOUtils;import com.ning.http.client.AsyncCompletionHandler;
import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.Request;
import com.ning.http.client.Response;/*** 描述:异步请求结果处理器* * **/
public class AsyncRequestResultHandler extends AsyncCompletionHandler {private AsyncHttpClient asyncHttpClient;private Request request;private int retryTimes;private int currentRetryTimes = 0;private static String TIMEOUT_STATUS = "408";public AsyncRequestResultHandler(AsyncHttpClient asyncHttpClient, Request request, int retryTimes){this.asyncHttpClient = asyncHttpClient;this.request = request;this.retryTimes = retryTimes;}/*** 响应异常*/public void onThrowable(Throwable t) {t.printStackTrace();if(!Thread.currentThread().isInterrupted()) {if (currentRetryTimes < retryTimes) {currentRetryTimes++;System.out.println("current retry times: "+currentRetryTimes+", max retry times: "+retryTimes);try {asyncHttpClient.executeRequest(request, this);} catch (Exception e) {System.err.println("retry execute request error");}return;}}System.exit(0);}     /*** 响应返回*/public Object onCompleted(Response response) throws Exception {//获取响应报文内容//String[] headerNames = response.getHeaders().keySet().toArray(new String[0]);byte[] responseBody;String contentEncoding = "GBK";if (contentEncoding != null && contentEncoding.toLowerCase().contains("gzip")) {try {responseBody = IOUtils.toByteArray(new GZIPInputStream(response.getResponseBodyAsStream()));}catch (Exception e){responseBody = IOUtils.toByteArray(response.getResponseBodyAsStream());}} else {responseBody = IOUtils.toByteArray(response.getResponseBodyAsStream());}//System.out.println("返回内容utf-8:"+new String(responseBody,"utf-8"));String body=new String(responseBody,"GBK");System.out.println("返回内容:"+body);System.exit(0);return responseBody;}}

小结

本文通过实现一个基于 async-http-client 的异步 HTTP 请求工具,展示了如何高效地发送 HTTP 请求并处理响应数据。通过工具类 EncodingUtil 和异步请求结果处理器 AsyncRequestResultHandler,解决了字符编码和响应数据处理的问题,提高了程序的健壮性和易用性。


http://www.ppmy.cn/server/165930.html

相关文章

【零基础学Mysql】常用函数讲解,提升数据操作效率的利器

以耳倾听世间繁华&#xff0c;以语表达心中所想 大家好,我是whisperrrr. 前言&#xff1a; 大家好&#xff0c;我是你们的朋友whisrrr。在日常工作中&#xff0c;MySQL作为一款广泛使用的开源关系型数据库&#xff0c;其强大的功能为我们提供了便捷的数据存储和管理手段。而在…

【前端】【面试】【经典一道题】前端 Vue、React 采用单向数据流的原因

前端Vue、React采用单向数据流的原因 一、可预测性 1. 数据流向清晰 在单向数据流架构里&#xff0c;数据从父组件流向子组件的路径是明确且可预期的。 React示例&#xff1a;父组件通过 props 传递数据给子组件&#xff0c;子组件只能读取 props 中的数据&#xff0c;没有直…

快速对QWen2.5大模型进行微调

先看看训练结果&#xff1a; 目录 前言什么是LLaMA-Factory&#xff1f;安装LLaMA-Factory准备数据集配置微调参数运行微调脚本评估和保存模型使用微调后的模型可视化微调大模型总结 前言 在当今人工智能领域&#xff0c;大模型&#xff08;如LLaMA、GPT等&#xff09;的微调…

OpenCV4.8 开发实战系列专栏之 30 - OpenCV中的自定义滤波器

欢迎大家学习OpenCV4.8 开发实战专栏&#xff0c;长期更新&#xff0c;不断分享源码。 专栏代码全部基于C 与Python双语演示。 送相关学习资料, V&#xff1a; OpenCVXueTang_Asst 本文关键知识点&#xff1a;OpenCV中的自定义滤波器 图像卷积最主要功能有图像模糊、锐化、梯…

c++ 面试题

C 面试题通常涵盖基础知识、面向对象编程、内存管理、模板、STL&#xff08;标准模板库&#xff09;等方面。以下是一些常见的 C 面试题及其简要解答&#xff0c;供你参考&#xff1a; 1. C 基础知识 1.1 C 和 C 的区别是什么&#xff1f; C 是 C 的超集&#xff0c;支持面向…

【HarmonyOS NEXT】设备显示白屏 syswarning happended in XXX

【HarmonyOS NEXT】设备显示白屏 syswarning happended in XXX 一、问题背景&#xff1a; 运行启动鸿蒙应用项目&#xff0c;设备显示白屏&#xff0c;IDE左下角提示syswarning happended in XXX设备名。 点击Jump to Log提示如下&#xff1a; Device info:HUAWEI Mate 60 …

基于keepalived+GTID半同步主从复制的高可用MySQL集群

文章目录 项目架构图项目名称项目环境项目描述ip地址规划项目步骤一.安装好8台全新的centos7.9的系统&#xff0c;关闭firewalld和selinux&#xff0c;配置每台主机的静态ip地址&#xff0c;设置每台主机对应的主机名。1、关闭firewalld2.关闭seLinux3.配置每台主机静态ip地址4…

使用 Three.js 实现火焰效果

大家好&#xff01;我是 [数擎 AI]&#xff0c;一位热爱探索新技术的前端开发者&#xff0c;在这里分享前端和 Web3D、AI 技术的干货与实战经验。如果你对技术有热情&#xff0c;欢迎关注我的文章&#xff0c;我们一起成长、进步&#xff01; 开发领域&#xff1a;前端开发 | A…