Java 使用 HttpClient 发送 GET请求和 POST请求
作者:梅小西爱学习 发布时间:2023-07-23 07:56:13
概述
日常工作中,我们经常会有发送 HTTP 网络请求的需求,概括下我们常见的发送 HTTP 请求的需求内容:
可以发送基本的 GET/POST/PUT/DELETE 等请求;
HTTP请求,可以附带认证,包括基本的 用户名/密码 认证,以及 Bearer Token 认证;
请求可以自定义 超时时间;
HTTP请求可以带参数,也可以不带参数;
HTTP请求返回结果,可以直接传入一个 Class,这样结果就不用二次解析;
请求的路径可以是 url,也可以是 Uri;
针对以上常见的 HTTP 请求,在 HttpClient 的基础上做了二次封装,可以直接简单、高效地发送HTTP请求。
本文所使用的的 HttpClient 版本为 4.5.3,pom依赖如下:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
认证方式
HTTP请求中,常用的认证方式包括:
用户名 + 密码 认证
Bearer Token 认证
其实这些认证的本质,都是通过在 HTTP Request Header 中,添加固定的参数,如下格式:
Authorization: token字符串
上面的Authorization 就是 HTTP Header 的 key,而 token字符串 就是具体的认证方式中需要传递的参数。
我们将所有的认证方式,都抽象为 Auth 类,并定义方法 getAuth 方法,由具体的子类去实现,返回自定义认证方式中所需要的token字符串。
基础认证Auth
public interface Auth {
String getAuth();
}
用户名密码认证
BasicAuth,用于做用户名和密码认证,代码如下:
public class BasicAuth implements Auth {
private String username;
private String password;
public BasicAuth(String username, String password) {
this.username = username;
this.password = password;
}
@Override
public String getAuth() {
String auth = String.format("%s:%s", this.username, this.password);
byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(StandardCharsets.ISO_8859_1));
return "Basic " + new String(encodedAuth);
}
}
Bearer Token 认证
BearerAuth,用于做 Bearer Token认证,代码如下:
public class BearerAuth implements Auth {
private String token;
public BearerAuth(String token) {
this.token = token;
}
@Override
public String getAuth() {
return "Bearer " + this.token;
}
}
上面介绍了两种常用的认证方式,如果有其他的认证方式,实现 Auth 接口的 getAuth 方法即可。
这个 Auth 我们会在真正发送 HTTP 请求时用到。
配置超时
HttpClient中,通过 setDefaultRequestConfig 来设置请求的参数配置,包括请求超时时间等。
生成 RequestConfig
/**
* 设置 HTTP 请求超时时间
*
* @param connectTimeout tcp 连接超时时间
* @param readTimeout 读取数据超时时间
* @return
*/
private RequestConfig getRequestConfig(int connectTimeout, int readTimeout) {
return RequestConfig.custom()
.setConnectTimeout(connectTimeout)
.setConnectionRequestTimeout(connectTimeout)
.setSocketTimeout(readTimeout)
.build();
}
设置超时时间
HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
.build();
到这里,HttpClient所需要做的一些配置,基本就结束了,下面将展示完整的代码示例。
完整代码 HttpRequestClient
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.http.HttpMethod;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
/**
* @author wxweven
*/
@Slf4j
public class HttpRequestClient {
// 默认 连接/读取数据 超时时间都是 10s
private static final int DEFAULT_CONNECT_TIMEOUT = 10_000;
private static final int DEFAULT_READ_TIMEOUT = 10_000;
private static final Gson GSON = new Gson();
private Auth auth;
private HttpClient httpClient;
// 用户名密码认证,默认的超时时间(10s)
public HttpRequestClient(String username, String password) {
this(username, password,
DEFAULT_CONNECT_TIMEOUT,
DEFAULT_READ_TIMEOUT
);
}
// 用户名密码认证,自定义超时时间
public HttpRequestClient(String username, String password,
int connectTimeout, int readTimeout) {
this.auth = new BasicAuth(username, password);
this.httpClient = HttpClientBuilder.create()
.setDefaultRequestConfig(getRequestConfig(connectTimeout, readTimeout))
.build();
}
// BearerToken 认证,默认的超时时间(10s)
public HttpRequestClient(String bearerToken) {
this(bearerToken,
DEFAULT_CONNECT_TIMEOUT,
DEFAULT_READ_TIMEOUT
);
}
// BearerToken 认证,自定义超时时间
public HttpRequestClient(String bearerToken,
int connectTimeout, int readTimeout) {
this.auth = new BearerAuth(bearerToken);
this.httpClient = HttpClientBuilder.create()
.setDefaultRequestConfig(getRequestConfig(connectTimeout, readTimeout))
.build();
}
/**
* 设置 HTTP 请求超时时间
*
* @param connectTimeout tcp 连接超时时间
* @param readTimeout 读取数据超时时间
* @return
*/
private RequestConfig getRequestConfig(int connectTimeout, int readTimeout) {
return RequestConfig.custom()
.setConnectTimeout(connectTimeout)
.setConnectionRequestTimeout(connectTimeout)
.setSocketTimeout(readTimeout)
.build();
}
/**
* 发送 GET 请求,不带参数
*
* @param url
* @return
*/
public String doGet(String url) {
return doGet(url, new HashMap<>());
}
/**
* 发送 GET 请求,不带参数
*
* @param uri
* @return
*/
public String doGet(URI uri) {
return doGet(uri, new HashMap<>());
}
/**
* 发送 GET 请求,K-V 形式参数
*
* @param url
* @param params
* @return
*/
public String doGet(String url, Map<String, String> params) {
RequestBuilder reqBuilder = RequestBuilder.get(url);
return doGet(reqBuilder, params);
}
/**
* 发送 GET 请求,K-V 形式参数
*
* @param uri
* @param params
* @return
*/
public String doGet(URI uri, Map<String, String> params) {
RequestBuilder reqBuilder = RequestBuilder.get(uri);
return doGet(reqBuilder, params);
}
public String doGet(RequestBuilder reqBuilder, Map<String, String> params) {
reqBuilder.addHeader(HttpHeaders.AUTHORIZATION, auth.getAuth());
for (Map.Entry<String, String> entry : params.entrySet()) {
reqBuilder.addParameter(entry.getKey(), entry.getValue());
}
try {
HttpResponse resp = httpClient.execute(reqBuilder.build());
return EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8);
} catch (IOException e) {
log.error("doGet 异常: reqBuilder={}, params={}", reqBuilder, params, e);
return null;
}
}
/***
* 发送 GET 请求,不带参数,返回指定类型的 class
* @param url 请求的 url
* @param responseType 返回类型
* @param <T>
* @return
*/
public <T> T getForObject(String url, Class<T> responseType) {
RequestBuilder reqBuilder = RequestBuilder.get(url);
return getForObject(reqBuilder, responseType);
}
/***
* 发送 GET 请求,不带参数,返回指定类型的 class
* @param uri 请求的 uri
* @param responseType 返回类型
* @param <T>
* @return
*/
public <T> T getForObject(URI uri, Class<T> responseType) {
RequestBuilder reqBuilder = RequestBuilder.get(uri);
return getForObject(reqBuilder, responseType);
}
public <T> T getForObject(RequestBuilder reqBuilder, Class<T> responseType) {
reqBuilder.addHeader(HttpHeaders.AUTHORIZATION, auth.getAuth());
try {
HttpResponse resp = httpClient.execute(reqBuilder.build());
String result = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8);
return GSON.fromJson(result, responseType);
} catch (IOException e) {
log.error("getForObject 异常: reqBuilder={}, responseType={}", reqBuilder, responseType, e);
return null;
}
}
/**
* 发送 POST 请求,JSON 形式
*
* @param url
* @param json json字符串
* @return
*/
public String doPost(String url, String json) {
try {
HttpResponse resp = this.exchange(HttpMethod.POST, url, json);
return EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8);
} catch (IOException e) {
log.error("doPost 异常: url={}, json={}", url, json, e);
return null;
}
}
/**
* 发送 POST 请求,JSON 形式,返回 HttpResponse
*
* @param url
* @param json json字符串
* @return
*/
public HttpResponse doPostResp(String url, String json) {
return this.exchange(HttpMethod.POST, url, json);
}
/**
* 发送 PUT 请求,JSON 形式
*
* @param url
* @param json json字符串
* @return
*/
public HttpResponse doPut(String url, String json) {
return this.exchange(HttpMethod.PUT, url, json);
}
/**
* 发送 PUT 请求,JSON 形式
*
* @param url
* @param json json字符串
* @return
*/
public HttpResponse doDelete(String url, String json) {
return this.exchange(HttpMethod.DELETE, url, json);
}
public HttpResponse exchange(HttpMethod method, String url, String json) {
RequestBuilder reqBuilder = RequestBuilder.create(method.toString())
.setUri(url)
.addHeader(HttpHeaders.AUTHORIZATION, auth.getAuth())
.addHeader("Accept", ContentType.APPLICATION_JSON.toString())
.addHeader("Content-type", ContentType.APPLICATION_JSON.toString());
if (StringUtils.isNotBlank(json)) {
reqBuilder.setEntity(new StringEntity(json, ContentType.APPLICATION_JSON));
}
try {
return httpClient.execute(reqBuilder.build());
} catch (IOException e) {
log.error("doPost 异常: url={}, json={}", url, json, e);
return null;
}
}
}
来源:https://juejin.cn/post/6998826369819869215
猜你喜欢
- 井字棋游戏要求在3乘3棋盘上,每行都相同或者每列都相同再或者对角线相同,则胜出.因此我们可以使用一个二维数组来表示棋盘,判断胜负只需要判断数
- C语言/C++怎样产生随机数:这里要用到的是rand()函数, srand()函数,和time()函数。需要说明的是,iostream头文件
- 本文实例为大家分享了C语言实现贪吃蛇游戏的具体代码,供大家参考,具体内容如下IDE用的是 VS2019先看效果 代码全览game.
- PS:本文包含了大部分strings函数的说明,并附带举例说明。本来想自己整理一下的,发现已经有前辈整理过了,就转了过来。修改了原文一些源码
- 前言在网络通信中,通信传输数据容易被截取或篡改,如果在传输用户隐私数据过程中,被不法分子截取或篡改,就可能导致用户受到伤害,比如被诈 骗,所
- 概述:Flutter 标签类控件大全ChipFlutter内置了多个标签类控件,但本质上它们都是同一个控件,只不过是属性参数不同而已,在学习
- 1.map遍历快速实现边距,文字自适应改变大小Container( // padding: EdgeI
- 一、前言(吐槽+煽情+简介) &n
- 本文主要介绍我为桌面和 Web 设计的一个超级秘密 Flutter 项目使用了画布和可拖动节点界面。本教程将展示我如何使用堆栈来使用小部件完
- 最近没事写了一个简易浏览器,在刚开始写的时候遇到一些问题,主要的问题就是如何在自己的webview中显示所有的网页数据,不过不指
- Java BufferWriter写文件之后文件是空的或者数据不全在编程的过程中,读写文件是非常常见的操作,在这里我问介绍一下最近我遇到的集
- 背景今天面试字节算法岗时被问到的问题,让我用C++实现一个softmax函数。softmax是逻辑回归在多分类问题上的推广。大概的公式如下:
- 1、取得控制台应用程序的根目录方法方法1、Environment.CurrentDirectory 取得或设置当前工作目录的完整限定路径方法
- iOS定位 - 普通定位(没有地图) - 反地理编码(得到具体位置),下面通过代码给大家详解,代码如下:#import <CoreLo
- 声明:下面的实例全部在linux下尝试,window下未尝试。有兴趣者可以试一下。文章针c初学者。c语言的强符号和弱符号是c初学者经常容易犯
- 本文实例讲述了C++实现的链表类。分享给大家供大家参考。具体如下:#include <iostream>using namesp
- 背景:在Android中按照数据保存的方式,可以分为如下几种Content Provider (用的SQLite实现),SQLite,Sha
- 网络中数据传输经常是xml或者json,现在做的一个项目之前调其他系统接口都是返回的xml格式,刚刚遇到一个返回json格式数据的接口,通过
- 在导入studio工程的时候,进行sync的时候,提示Error:Configuration with name 'default&
- 相比于直线检测,直线拟合的最大特点是将所有数据只拟合出一条直线void fitLine( InputArray points, Output