|
|
@@ -30,6 +30,7 @@ import java.util.List;
|
|
|
import java.util.Map;
|
|
|
import java.util.Optional;
|
|
|
import java.util.function.Consumer;
|
|
|
+import java.util.regex.Pattern;
|
|
|
|
|
|
|
|
|
/**
|
|
|
@@ -73,6 +74,23 @@ public class RequestComponent {
|
|
|
return webClient;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 创建无SSL的WebClient
|
|
|
+ *
|
|
|
+ * @return WebClient
|
|
|
+ */
|
|
|
+ private WebClient selectNoSSLWebClient() {
|
|
|
+ try {
|
|
|
+ if (webClientConfig != null) {
|
|
|
+ return webClientConfig.clientBuilder();
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ log.info("创建安全WebClient失败,使用默认WebClient", e);
|
|
|
+ }
|
|
|
+ return webClient;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 从URL中提取域名
|
|
|
*
|
|
|
@@ -271,6 +289,107 @@ public class RequestComponent {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 发送post请求,返回的content-type:text/json;charset=UTF-8
|
|
|
+ *
|
|
|
+ * @param url 请求地址
|
|
|
+ * @param body 请求体
|
|
|
+ * @param responseClass 响应类
|
|
|
+ * @param headers 请求头
|
|
|
+ * @param <Response> 响应实体
|
|
|
+ * @return <Response> ResponseEntity<Response> 响应
|
|
|
+ */
|
|
|
+ public <Response> ResponseEntity<Response> post2(String url, String body, Class<Response> responseClass, HttpHeaders headers) {
|
|
|
+ body = Optional.ofNullable(body).orElse("");
|
|
|
+ log.info("URL的值:{},body的值:{}", url, body);
|
|
|
+ WebClient webClient = selectNoSSLWebClient();
|
|
|
+ try {
|
|
|
+ // 先获取原始响应字符串
|
|
|
+ Mono<String> responseMono = webClient.post()
|
|
|
+ .uri(url)
|
|
|
+ .headers(setHeaders(headers))
|
|
|
+ .header(HttpHeaders.ACCEPT, "application/json,text/html,text/json,*/*")
|
|
|
+ .header(HttpHeaders.ACCEPT_LANGUAGE, "zh-CN,zh;q=0.9")
|
|
|
+ .header(HttpHeaders.CACHE_CONTROL, "no-cache")
|
|
|
+ .body(BodyInserters.fromValue(body))
|
|
|
+ .retrieve()
|
|
|
+ .bodyToMono(String.class);
|
|
|
+
|
|
|
+ // 处理响应:过滤非法字符并解析JSON
|
|
|
+ Mono<Response> resultMono = responseMono.flatMap(rawResponse -> {
|
|
|
+ // 过滤非法字符
|
|
|
+ String filteredResponse = filterIllegalCharacters(rawResponse);
|
|
|
+ try {
|
|
|
+ // 使用FastJSON手动解析JSON
|
|
|
+ Response result = JSON.parseObject(filteredResponse, responseClass);
|
|
|
+ return Mono.just(result);
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 如果JSON解析失败,抛出异常
|
|
|
+ return Mono.error(new WebClientResponseException(
|
|
|
+ 500,
|
|
|
+ "JSON parsing failed after filtering: " + e.getMessage(),
|
|
|
+ HttpHeaders.EMPTY,
|
|
|
+ filteredResponse.getBytes(StandardCharsets.UTF_8),
|
|
|
+ null
|
|
|
+ ));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // 等待结果并构建ResponseEntity
|
|
|
+ Response result = resultMono.block();
|
|
|
+ HttpHeaders responseHeaders = new HttpHeaders();
|
|
|
+ responseHeaders.setContentType(MediaType.APPLICATION_JSON);
|
|
|
+ // 获取原始响应状态码
|
|
|
+ ResponseEntity<String> rawResponse = webClient.post()
|
|
|
+ .uri(url)
|
|
|
+ .headers(setHeaders(headers))
|
|
|
+ .header(HttpHeaders.ACCEPT, "application/json,text/html,text/json,*/*")
|
|
|
+ .header(HttpHeaders.ACCEPT_LANGUAGE, "zh-CN,zh;q=0.9")
|
|
|
+ .header(HttpHeaders.CACHE_CONTROL, "no-cache")
|
|
|
+ .body(BodyInserters.fromValue(body))
|
|
|
+ .retrieve()
|
|
|
+ .toEntity(String.class)
|
|
|
+ .block();
|
|
|
+
|
|
|
+ int statusCode = rawResponse != null ? rawResponse.getStatusCode().value() : 200;
|
|
|
+ return ResponseEntity.status(statusCode).headers(responseHeaders).body(result);
|
|
|
+ } catch (WebClientResponseException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ throw e;
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 处理其他异常
|
|
|
+ throw new WebClientResponseException(
|
|
|
+ 500,
|
|
|
+ "Request failed: " + e.getMessage(),
|
|
|
+ HttpHeaders.EMPTY,
|
|
|
+ e.getMessage().getBytes(StandardCharsets.UTF_8),
|
|
|
+ null
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构造post请求
|
|
|
+ *
|
|
|
+ * @param url
|
|
|
+ * @param body
|
|
|
+ * @param responseClass
|
|
|
+ * @param headers
|
|
|
+ * @param <Response>
|
|
|
+ * @return ResponseEntity<Response>
|
|
|
+ */
|
|
|
+ public <Response> ResponseEntity<Response> postWithMono(String url, String body, Class<Response> responseClass, HttpHeaders headers) {
|
|
|
+ WebClient webClient = selectNoSSLWebClient();
|
|
|
+ return webClient.post()
|
|
|
+ .uri(url)
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
+ .headers(setHeaders(headers))
|
|
|
+ .bodyValue(body)
|
|
|
+ .retrieve()
|
|
|
+ .toEntity(responseClass)
|
|
|
+ .block();
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* gbk
|
|
|
*
|
|
|
@@ -648,4 +767,28 @@ public class RequestComponent {
|
|
|
.block();
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 过滤JSON字符串中的非法控制字符
|
|
|
+ * 只允许 \r, \n, \t 等标准空白字符
|
|
|
+ *
|
|
|
+ * @param jsonStr 原始JSON字符串
|
|
|
+ * @return String 过滤后的JSON字符串
|
|
|
+ */
|
|
|
+ private String filterIllegalCharacters(String jsonStr) {
|
|
|
+ if (jsonStr == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ // 正则表达式匹配非法控制字符(除了 \r, \n, \t 之外的所有控制字符)
|
|
|
+ // ASCII 0-31 除了 9(\t), 10(\n), 13(\r) 之外的所有控制字符
|
|
|
+ Pattern pattern = Pattern.compile("[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f]");
|
|
|
+ String filtered = pattern.matcher(jsonStr).replaceAll("");
|
|
|
+
|
|
|
+ if (!jsonStr.equals(filtered)) {
|
|
|
+ log.warn("过滤掉了 {} 个非法控制字符", jsonStr.length() - filtered.length());
|
|
|
+ log.debug("过滤前: {}", jsonStr);
|
|
|
+ log.debug("过滤后: {}", filtered);
|
|
|
+ }
|
|
|
+ return filtered;
|
|
|
+ }
|
|
|
+
|
|
|
}
|