Java转发请求库
日常接入第三方需要转发 HTTP 请求, 这种在 SpringBoot 当中有个 RestTemplate 请求工具,
但是日常使用过程当中这个原始库编写十分麻烦, 所以不推荐直接集成编写.
这里推荐用 SpringBoot 内部另外的类库: webflux, 这里先引入下依赖:
<dependencies>
<!-- HTTP转发请求 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- Netty工具,依赖异步转发等工具 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-reactor-netty</artifactId>
</dependency>
</dependencies>
之后就是编写具体请求库功能:
package com.app.fox.utils;
import com.fasterxml.jackson.databind.JsonNode;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;
import javax.net.ssl.SSLException;
import reactor.netty.http.client.HttpClient;
import java.time.Duration;
import java.util.Map;
import java.util.function.Consumer;
/**
* 构建转发请求工具
*/
public class RequestUtils {
/**
* 将URL和参数构建 example.com?xxx=yyy 方式
*
* @param path 请求地址
* @param params 请求参数
* @return String
*/
public static String getRequestComposePath(String path, MultiValueMap<String, String> params) {
return params == null ? path : UriComponentsBuilder.fromHttpUrl(path).queryParams(params).toUriString();
}
/**
* 构建忽略SSL证书请求
*
* @return WebClient
*/
public static WebClient createIgnoreSslWebClient() {
try {
SslContext ssl = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
HttpClient client = HttpClient.create().secure(t -> t.sslContext(ssl));
return WebClient.builder().clientConnector(new ReactorClientHttpConnector(client)).build();
} catch (SSLException exception) {
throw new RuntimeException(exception);
}
}
/**
* 转发推送Get请求数据
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param clazz 响应类型数据
* @param <T> Mono 特化类型
* @return T
*/
public static <T> Mono<T> getRequestSend(String path, MultiValueMap<String, String> params, Map<String, String> headers, Class<T> clazz) {
String uri = getRequestComposePath(path, params);
WebClient.RequestHeadersSpec<?> requestHeadersSpec = createIgnoreSslWebClient().get().uri(uri);
if (headers != null) {
headers.forEach(requestHeadersSpec::header);
}
return requestHeadersSpec.retrieve().bodyToMono(clazz);
}
/**
* 同步推送Get请求
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param clazz 响应类型数据
* @param <T> Mono 特化类型
* @return T
*/
public static <T> T getRequestSync(String path, MultiValueMap<String, String> params, Map<String, String> headers, Class<T> clazz) {
Mono<T> response = getRequestSend(path, params, headers, clazz);
return response.block();
}
/**
* 同步推送Get请求 - 含超时: 秒
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param clazz 响应类型数据
* @param timeoutSec 超时
* @param <T> Mono 特化类型
* @return T
*/
public static <T> T getRequestSync(String path, MultiValueMap<String, String> params, Map<String, String> headers, Class<T> clazz, long timeoutSec) {
Mono<T> response = getRequestSend(path, params, headers, clazz);
return response.block(Duration.ofSeconds(timeoutSec));
}
/**
* 异步推送Get请求
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param clazz 回调类型
* @param cb 异步回调处理
* @param <T> 回调类型
*/
public static <T> void getRequest(String path, MultiValueMap<String, String> params, Map<String, String> headers, Class<T> clazz, Consumer<T> cb) {
Mono<T> response = getRequestSend(path, params, headers, clazz);
response.subscribe(cb);
}
/**
* 异步推送Get请求
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param cb 异步回调处理
*/
public static void getRequestJson(String path, MultiValueMap<String, String> params, Map<String, String> headers, Consumer<JsonNode> cb) {
getRequest(path, params, headers, JsonNode.class, cb);
}
// -------------------------------------------------------------------------------
/**
* 转发推送Post请求数据
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param clazz 响应类型数据
* @param <T> Mono 特化类型
* @return T
*/
public static <T> Mono<T> postRequestSend(String path, MultiValueMap<String, String> params, Map<String, String> headers, Class<T> clazz) {
String uri = getRequestComposePath(path, params);
WebClient.RequestBodySpec requestBodySpec = createIgnoreSslWebClient().post().uri(uri);
if (headers != null) {
headers.forEach(requestBodySpec::header);
}
return requestBodySpec.body(BodyInserters.fromMultipartData(params)).retrieve().bodyToMono(clazz);
}
/**
* 同步推送Post请求
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param clazz 响应类型数据
* @param <T> Mono 特化类型
* @return T
*/
public static <T> T postRequestSync(String path, MultiValueMap<String, String> params, Map<String, String> headers, Class<T> clazz) {
Mono<T> response = postRequestSend(path, params, headers, clazz);
return response.block();
}
/**
* 同步推送Post请求 - 含超时: 秒
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param clazz 响应类型数据
* @param timeoutSec 超时
* @param <T> Mono 特化类型
* @return T
*/
public static <T> T postRequestSync(String path, MultiValueMap<String, String> params, Map<String, String> headers, Class<T> clazz, long timeoutSec) {
Mono<T> response = postRequestSend(path, params, headers, clazz);
return response.block(Duration.ofSeconds(timeoutSec));
}
/**
* 异步推送Post请求
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param clazz 回调类型
* @param cb 异步回调处理
* @param <T> 回调类型
*/
public static <T> void postRequest(String path, MultiValueMap<String, String> params, Map<String, String> headers, Class<T> clazz, Consumer<T> cb) {
Mono<T> response = postRequestSend(path, params, headers, clazz);
response.subscribe(cb);
}
/**
* 异步推送Post请求
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param cb 异步回调处理
*/
public static void postRequestJson(String path, MultiValueMap<String, String> params, Map<String, String> headers, Consumer<JsonNode> cb) {
postRequest(path, params, headers, JsonNode.class, cb);
}
// -------------------------------------------------------------------------------
/**
* 转发推送Put请求数据
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param clazz 响应类型数据
* @param <T> Mono 特化类型
* @return T
*/
public static <T> Mono<T> putRequestSend(String path, MultiValueMap<String, String> params, Map<String, String> headers, Class<T> clazz) {
String uri = getRequestComposePath(path, params);
WebClient.RequestBodySpec requestBodySpec = createIgnoreSslWebClient().put().uri(uri);
if (headers != null) {
headers.forEach(requestBodySpec::header);
}
return requestBodySpec.body(BodyInserters.fromMultipartData(params)).retrieve().bodyToMono(clazz);
}
/**
* 同步推送Put请求
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param clazz 响应类型数据
* @param <T> Mono 特化类型
* @return T
*/
public static <T> T putRequestSync(String path, MultiValueMap<String, String> params, Map<String, String> headers, Class<T> clazz) {
Mono<T> response = putRequestSend(path, params, headers, clazz);
return response.block();
}
/**
* 同步推送Put请求 - 含超时: 秒
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param clazz 响应类型数据
* @param timeoutSec 超时
* @param <T> Mono 特化类型
* @return T
*/
public static <T> T putRequestSync(String path, MultiValueMap<String, String> params, Map<String, String> headers, Class<T> clazz, long timeoutSec) {
Mono<T> response = putRequestSend(path, params, headers, clazz);
return response.block(Duration.ofSeconds(timeoutSec));
}
/**
* 异步推送Put请求
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param clazz 回调类型
* @param cb 异步回调处理
* @param <T> 回调类型
*/
public static <T> void putRequest(String path, MultiValueMap<String, String> params, Map<String, String> headers, Class<T> clazz, Consumer<T> cb) {
Mono<T> response = putRequestSend(path, params, headers, clazz);
response.subscribe(cb);
}
/**
* 异步推送Put请求
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param cb 异步回调处理
*/
public static void putRequestJson(String path, MultiValueMap<String, String> params, Map<String, String> headers, Consumer<JsonNode> cb) {
putRequest(path, params, headers, JsonNode.class, cb);
}
// -------------------------------------------------------------------------------
/**
* 转发推送Patch请求数据
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param clazz 响应类型数据
* @param <T> Mono 特化类型
* @return T
*/
public static <T> Mono<T> patchRequestSend(String path, MultiValueMap<String, String> params, Map<String, String> headers, Class<T> clazz) {
String uri = getRequestComposePath(path, params);
WebClient.RequestBodySpec requestBodySpec = createIgnoreSslWebClient().patch().uri(uri);
if (headers != null) {
headers.forEach(requestBodySpec::header);
}
return requestBodySpec.body(BodyInserters.fromMultipartData(params)).retrieve().bodyToMono(clazz);
}
/**
* 同步推送Patch请求
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param clazz 响应类型数据
* @param <T> Mono 特化类型
* @return T
*/
public static <T> T patchRequestSync(String path, MultiValueMap<String, String> params, Map<String, String> headers, Class<T> clazz) {
Mono<T> response = patchRequestSend(path, params, headers, clazz);
return response.block();
}
/**
* 同步推送Patch请求 - 含超时: 秒
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param clazz 响应类型数据
* @param timeoutSec 超时
* @param <T> Mono 特化类型
* @return T
*/
public static <T> T patchRequestSync(String path, MultiValueMap<String, String> params, Map<String, String> headers, Class<T> clazz, long timeoutSec) {
Mono<T> response = patchRequestSend(path, params, headers, clazz);
return response.block(Duration.ofSeconds(timeoutSec));
}
/**
* 异步推送Patch请求
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param clazz 回调类型
* @param cb 异步回调处理
* @param <T> 回调类型
*/
public static <T> void patchRequest(String path, MultiValueMap<String, String> params, Map<String, String> headers, Class<T> clazz, Consumer<T> cb) {
Mono<T> response = patchRequestSend(path, params, headers, clazz);
response.subscribe(cb);
}
/**
* 异步推送Patch请求
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param cb 异步回调处理
*/
public static void patchRequestJson(String path, MultiValueMap<String, String> params, Map<String, String> headers, Consumer<JsonNode> cb) {
patchRequest(path, params, headers, JsonNode.class, cb);
}
// -------------------------------------------------------------------------------
/**
* 转发推送Delete请求数据
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param clazz 响应类型数据
* @param <T> Mono 特化类型
* @return T
*/
public static <T> Mono<T> deleteRequestSend(String path, MultiValueMap<String, String> params, Map<String, String> headers, Class<T> clazz) {
String uri = getRequestComposePath(path, params);
WebClient.RequestHeadersSpec<?> requestHeadersSpec = createIgnoreSslWebClient().delete().uri(uri);
if (headers != null) {
headers.forEach(requestHeadersSpec::header);
}
return requestHeadersSpec.retrieve().bodyToMono(clazz);
}
/**
* 同步推送Delete请求
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param clazz 响应类型数据
* @param <T> Mono 特化类型
* @return T
*/
public static <T> T deleteRequestSync(String path, MultiValueMap<String, String> params, Map<String, String> headers, Class<T> clazz) {
Mono<T> response = deleteRequestSend(path, params, headers, clazz);
return response.block();
}
/**
* 同步推送Delete请求 - 含超时: 秒
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param clazz 响应类型数据
* @param timeoutSec 超时
* @param <T> Mono 特化类型
* @return T
*/
public static <T> T deleteRequestSync(String path, MultiValueMap<String, String> params, Map<String, String> headers, Class<T> clazz, long timeoutSec) {
Mono<T> response = deleteRequestSend(path, params, headers, clazz);
return response.block(Duration.ofSeconds(timeoutSec));
}
/**
* 异步推送Delete请求
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param clazz 回调类型
* @param cb 异步回调处理
* @param <T> 回调类型
*/
public static <T> void deleteRequest(String path, MultiValueMap<String, String> params, Map<String, String> headers, Class<T> clazz, Consumer<T> cb) {
Mono<T> response = deleteRequestSend(path, params, headers, clazz);
response.subscribe(cb);
}
/**
* 异步推送Delete请求
*
* @param path 请求路径
* @param params 请求参数
* @param headers 请求头
* @param cb 异步回调处理
*/
public static void deleteRequestJson(String path, MultiValueMap<String, String> params, Map<String, String> headers, Consumer<JsonNode> cb) {
deleteRequest(path, params, headers, JsonNode.class, cb);
}
}
这个请求组件支持 GET/POST/PUT/PATCH/DELETE 几个标准功能请求, 涵盖了日常会用到推送转发机制, 这里测试个样例:
package com.app.fox;
import com.app.fox.utils.JwtUtils;
import com.app.fox.utils.RequestUtils;
import com.fasterxml.jackson.databind.JsonNode;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.SignatureAlgorithm;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
@SpringBootTest
class FoxApplicationTests {
@Test
void request() {
// 同步推送请求
String url = "https://www.bing.com";
String html = RequestUtils.getRequestSync(
url,
new LinkedMultiValueMap<>(0),
null,
String.class
);
System.out.println(html);
// 异步推送请求
RequestUtils.getRequest(
url,
new LinkedMultiValueMap<>(0),
null,
String.class,
System.out::println
);
// 推送登录
String bili = "https://passport.bilibili.com/x/passport-login/web/login";
MultiValueMap<String, String> params = new LinkedMultiValueMap<>() {{
put("source", new LinkedList<>() {{
add("main-fe-header");
}});
put("username", new LinkedList<>() {{
add("meteorcat");
}});
put("password", new LinkedList<>() {{
add("meteorcat");
}});
}};
JsonNode node = RequestUtils.postRequestSync(
bili,
params,
null,
JsonNode.class
);
System.out.println(node);
// 异步推送
RequestUtils.postRequest(
bili,
params,
null,
JsonNode.class,
System.out::println
);
}
}
这里就是完全支持同步和异步请求推送转发的HTTP库, 可以直接方便调用.