async-http-client使用示例

embedded/2025/2/8 17:21:59/

文章目录

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

概要

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/embedded/160583.html

相关文章

蓝耘智算平台使用DeepSeek教程

目录 一.平台架构与技术特点 二、DeepSeek R1模型介绍与优势 DeepSeek R1 模型简介 DeepSeek R1 模型优势 三.蓝耘智算平台使用DeepSeek教程 展望未来 耘元生代智算云是蓝耘科技推出的一款智算云平台有着以下特点&#xff1a; 一.平台架构与技术特点 基于 Kubernetes 原…

Linux之安装docker

一、检查版本和内核是否合格 Docker支持64位版本的CentOS 7和CentOS 8及更高版本&#xff0c;它要求Linux内核版本不低于3.10。 检查版本 cat /etc/redhat-release检查内核 uname -r二、Docker的安装 1、自动安装 Docker官方和国内daocloud都提供了一键安装的脚本&#x…

适用于 Windows 的 Zed 编辑器的非官方稳定版。通过 scoop 或 pwsh 脚本轻松安装。不隶属于 Zed Industries

一、软件介绍&#xff08;文末提供下载&#xff09; Zed&#xff0c;这是一款由 Atom 和 Tree-sitter 的创建者提供的高性能多人 Atom and Tree-sitter.。 二、macOS 和 Linux安装 在 macOS 和 Linux 上&#xff0c;您可以直接下载 Zed 或通过本地包管理器安装 Zed。 本地包…

海康威视豆干型网络相机QT的Demo

我用的时候海康官网在arm-linux相关SDK没有给DEMO&#xff0c;只在手册里给了参考代码。自己参考SDK提供的手册作了个QT的DEMO版本。 //main.c #include <QApplication> #include <QWidget> #include <QDebug> #include <QTimer> #include "Hikv…

深度学习01 神经网络

目录 神经网络 ​感知器 感知器的定义 感知器的数学表达 感知器的局限性 多层感知器&#xff08;MLP, Multi-Layer Perceptron&#xff09; 多层感知器的定义 多层感知器的结构 多层感知器的优势 偏置 偏置的作用 偏置的数学表达 神经网络的构造 ​神经网络的基本…

Java面试题及答案整理( 2022最新版,持续更新)

发现网上很多Java面试题都没有答案&#xff0c;所以花了很长时间搜集整理出来了这套Java面试题大全&#xff0c;希望对大家有帮助哈~ Java面试永远是程序员迈向成功的第一个门槛&#xff0c;想要面试成功&#xff0c;各种面试题的洗礼是必不可少的&#xff0c;下面就来看看小编…

使用PyCharm创建项目以及如何注释代码

创建好项目后会出现如下图所示的画面&#xff0c;我们可以通过在项目文件夹上点击鼠标右键&#xff0c;选择“New”菜单下的“Python File”来创建一个 Python 文件&#xff0c;在给文件命名时建议使用英文字母和下划线的组合&#xff0c;创建好的 Python 文件会自动打开&#…

dl学习笔记(9):pytorch数据处理的完整流程

1&#xff09;自动导入常用库的设置方式 在开始之前&#xff0c;这里介绍一下自动导入常用的你需要加载的库的操作方式。 首先在我们的目录下找到ipython文件&#xff0c;如下图&#xff1a; 然后找到里面的startup文件&#xff1a; 然后新建一个文本文档&#xff0c;输入你每…