refactor(pdd): pdd.goods.image.upload 改为官方 urlencoded + Base64 image
- 与开放平台 curl/SDK 一致,不再 multipart - 移除 image-upload-api-type/gateway/multipart-field 配置项 Made-with: Cursor
This commit is contained in:
parent
349dbca470
commit
757e169ad5
|
|
@ -53,11 +53,8 @@ external:
|
||||||
isbn-goods-property-ref-pid: 425
|
isbn-goods-property-ref-pid: 425
|
||||||
# 按 pdd.goods.cat.rule.get 中 goods_properties_rule 必填项自动补全 goods_properties
|
# 按 pdd.goods.cat.rule.get 中 goods_properties_rule 必填项自动补全 goods_properties
|
||||||
fill-goods-properties-from-cat-rule: true
|
fill-goods-properties-from-cat-rule: true
|
||||||
# 发品前 POP 图床上传(默认 pdd.goods.image.upload;img.upload 易报「接口不属于当前网关」)
|
# 发品前 pdd.goods.image.upload(urlencoded,image=Base64,与开放平台 curl/SDK 一致)
|
||||||
image-upload-enabled: true
|
image-upload-enabled: true
|
||||||
image-upload-api-type: pdd.goods.image.upload
|
|
||||||
image-upload-gateway-url: ""
|
|
||||||
image-upload-multipart-field: file
|
|
||||||
image-upload-max-bytes: 3145728
|
image-upload-max-bytes: 3145728
|
||||||
image-upload-allowed-host-suffixes:
|
image-upload-allowed-host-suffixes:
|
||||||
- etjbooks.com.cn
|
- etjbooks.com.cn
|
||||||
|
|
|
||||||
|
|
@ -52,9 +52,6 @@ external:
|
||||||
isbn-goods-property-ref-pid: 425
|
isbn-goods-property-ref-pid: 425
|
||||||
fill-goods-properties-from-cat-rule: true
|
fill-goods-properties-from-cat-rule: true
|
||||||
image-upload-enabled: true
|
image-upload-enabled: true
|
||||||
image-upload-api-type: pdd.goods.image.upload
|
|
||||||
image-upload-gateway-url: ""
|
|
||||||
image-upload-multipart-field: file
|
|
||||||
image-upload-max-bytes: 3145728
|
image-upload-max-bytes: 3145728
|
||||||
image-upload-allowed-host-suffixes:
|
image-upload-allowed-host-suffixes:
|
||||||
- etjbooks.com.cn
|
- etjbooks.com.cn
|
||||||
|
|
|
||||||
|
|
@ -28,22 +28,6 @@ public class ExternalPddProperties {
|
||||||
*/
|
*/
|
||||||
private boolean imageUploadEnabled = true;
|
private boolean imageUploadEnabled = true;
|
||||||
|
|
||||||
/**
|
|
||||||
* 图片上传接口 {@code type}。{@code pdd.goods.img.upload} 在部分网关会报「接口不属于当前网关」,
|
|
||||||
* 默认使用 {@code pdd.goods.image.upload};若应用仅授权文件空间接口可改为 {@code pdd.goods.filespace.image.upload}。
|
|
||||||
*/
|
|
||||||
private String imageUploadApiType = "pdd.goods.image.upload";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 图片上传专用网关;为空则与发品使用同一 {@link #gatewayUrl}(或请求里传入的 gateway)。
|
|
||||||
*/
|
|
||||||
private String imageUploadGatewayUrl = "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* multipart 中二进制字段名,一般为 {@code file};若对接文档要求 {@code image} 可改此项。
|
|
||||||
*/
|
|
||||||
private String imageUploadMultipartField = "file";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 单张图片最大下载字节(默认 3MB,与常见平台主图上限一致)
|
* 单张图片最大下载字节(默认 3MB,与常见平台主图上限一致)
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发品前将 {@code pdd.goods.add} 根 JSON 中的外链图片经 POP 图床上传接口(默认 {@code pdd.goods.image.upload})上传并替换 URL。
|
* 发品前将 {@code pdd.goods.add} 根 JSON 中的外链图片经 {@code pdd.goods.image.upload}(urlencoded + Base64 {@code image})上传并替换 URL。
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
|
|
@ -60,26 +60,17 @@ public class PddGoodsImageRehostService {
|
||||||
log.debug("[PDD] image rehost skipped (no URLs requiring upload)");
|
log.debug("[PDD] image rehost skipped (no URLs requiring upload)");
|
||||||
return goodsAddRootJson;
|
return goodsAddRootJson;
|
||||||
}
|
}
|
||||||
String uploadGateway = StringUtils.hasText(props.getImageUploadGatewayUrl())
|
log.info("[PDD] image rehost begin distinctUrls={} gatewayHost={}", toUpload.size(), hostForLog(gatewayUrl));
|
||||||
? props.getImageUploadGatewayUrl().trim() : gatewayUrl;
|
|
||||||
String apiType = StringUtils.hasText(props.getImageUploadApiType())
|
|
||||||
? props.getImageUploadApiType().trim() : "pdd.goods.image.upload";
|
|
||||||
String fileField = StringUtils.hasText(props.getImageUploadMultipartField())
|
|
||||||
? props.getImageUploadMultipartField().trim() : "file";
|
|
||||||
log.info("[PDD] image rehost begin distinctUrls={} apiType={} uploadGatewayHost={}",
|
|
||||||
toUpload.size(), apiType, hostForLog(uploadGateway));
|
|
||||||
Map<String, String> sourceToPdd = new LinkedHashMap<>();
|
Map<String, String> sourceToPdd = new LinkedHashMap<>();
|
||||||
for (String src : toUpload) {
|
for (String src : toUpload) {
|
||||||
if (sourceToPdd.containsKey(src)) {
|
if (sourceToPdd.containsKey(src)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
byte[] bytes = downloadImageBytes(src);
|
byte[] bytes = downloadImageBytes(src);
|
||||||
String filename = guessFilenameFromUrl(src);
|
String raw = pddPopClient.invokeGoodsImageUpload(gatewayUrl, clientId, clientSecret, accessToken, bytes);
|
||||||
String raw = pddPopClient.invokeGoodsImgUpload(uploadGateway, clientId, clientSecret, accessToken, bytes, filename,
|
|
||||||
apiType, fileField);
|
|
||||||
String pddUrl = PddOpenApiSupport.parseGoodsImgUploadUrl(raw);
|
String pddUrl = PddOpenApiSupport.parseGoodsImgUploadUrl(raw);
|
||||||
if (!StringUtils.hasText(pddUrl)) {
|
if (!StringUtils.hasText(pddUrl)) {
|
||||||
throw new IllegalStateException(apiType + " 失败: " + PddOpenApiSupport.formatError(raw));
|
throw new IllegalStateException("pdd.goods.image.upload 失败: " + PddOpenApiSupport.formatError(raw));
|
||||||
}
|
}
|
||||||
sourceToPdd.put(src, pddUrl);
|
sourceToPdd.put(src, pddUrl);
|
||||||
log.info("[PDD] image rehost ok srcSnippet={} bytes={} destSnippet={}",
|
log.info("[PDD] image rehost ok srcSnippet={} bytes={} destSnippet={}",
|
||||||
|
|
@ -263,26 +254,6 @@ public class PddGoodsImageRehostService {
|
||||||
&& b[8] == 'W' && b[9] == 'E' && b[10] == 'B' && b[11] == 'P';
|
&& b[8] == 'W' && b[9] == 'E' && b[10] == 'B' && b[11] == 'P';
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String guessFilenameFromUrl(String url) {
|
|
||||||
try {
|
|
||||||
String path = URI.create(url.trim()).getPath();
|
|
||||||
if (!StringUtils.hasText(path)) {
|
|
||||||
return "image.jpg";
|
|
||||||
}
|
|
||||||
int slash = path.lastIndexOf('/');
|
|
||||||
String name = slash >= 0 ? path.substring(slash + 1) : path;
|
|
||||||
if (!StringUtils.hasText(name) || name.length() > 200) {
|
|
||||||
return "image.jpg";
|
|
||||||
}
|
|
||||||
if (!name.contains(".")) {
|
|
||||||
return name + ".jpg";
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
} catch (Exception e) {
|
|
||||||
return "image.jpg";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applyImageMapping(JSONObject root, Map<String, String> mapping) {
|
private void applyImageMapping(JSONObject root, Map<String, String> mapping) {
|
||||||
if (mapping.isEmpty()) {
|
if (mapping.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ public final class PddOpenApiSupport {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析商品图上传成功体中的 URL(兼容 {@code goods_img_upload_response} / {@code goods_image_upload_response} / 文件空间等命名)。
|
* 解析 {@code pdd.goods.image.upload} 成功体中的 URL(兼容 {@code goods_image_upload_response} / {@code goods_img_upload_response} 等命名)。
|
||||||
*/
|
*/
|
||||||
public static String parseGoodsImgUploadUrl(String body) {
|
public static String parseGoodsImgUploadUrl(String body) {
|
||||||
if (!StringUtils.hasText(body)) {
|
if (!StringUtils.hasText(body)) {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.net.http.HttpClient;
|
import java.net.http.HttpClient;
|
||||||
|
|
@ -12,9 +11,9 @@ import java.net.http.HttpRequest;
|
||||||
import java.net.http.HttpResponse;
|
import java.net.http.HttpResponse;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.util.Base64;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 拼多多 POP HTTP 调用(application/x-www-form-urlencoded)。
|
* 拼多多 POP HTTP 调用(application/x-www-form-urlencoded)。
|
||||||
|
|
@ -24,7 +23,7 @@ import java.util.UUID;
|
||||||
* <li>{@link #invokeGoodsAdd} — {@code pdd.goods.add}:业务字段全部在表单顶层({@code sku_list}、{@code carousel_gallery} 等为 JSON 字符串),
|
* <li>{@link #invokeGoodsAdd} — {@code pdd.goods.add}:业务字段全部在表单顶层({@code sku_list}、{@code carousel_gallery} 等为 JSON 字符串),
|
||||||
* <b>无</b> {@code param_json}、<b>无</b> {@code version}</li>
|
* <b>无</b> {@code param_json}、<b>无</b> {@code version}</li>
|
||||||
* <li>{@link #invokeTopLevelBiz} — 如 {@code pdd.goods.cat.rule.get} 的 {@code cat_id}/{@code goods_id} 等顶层字段</li>
|
* <li>{@link #invokeTopLevelBiz} — 如 {@code pdd.goods.cat.rule.get} 的 {@code cat_id}/{@code goods_id} 等顶层字段</li>
|
||||||
* <li>{@link #invokeGoodsImgUpload} — 商品图上传(如 {@code pdd.goods.image.upload}),{@code multipart/form-data}</li>
|
* <li>{@link #invokeGoodsImageUpload} — {@code pdd.goods.image.upload}:{@code application/x-www-form-urlencoded},{@code image} 为 Base64</li>
|
||||||
* <li>{@link #invoke} — 仅当接口要求整包 {@code param_json} 时使用(少数场景)</li>
|
* <li>{@link #invoke} — 仅当接口要求整包 {@code param_json} 时使用(少数场景)</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
|
|
@ -55,7 +54,7 @@ public class PddPopClient {
|
||||||
params.put(e.getKey(), e.getValue());
|
params.put(e.getKey(), e.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return postSignedAndLog(gatewayUrl, clientId, clientSecret, "pdd.goods.add", params, logPayload);
|
return postSignedAndLog(gatewayUrl, clientId, clientSecret, "pdd.goods.add", params, logPayload, Duration.ofSeconds(60));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -71,7 +70,7 @@ public class PddPopClient {
|
||||||
params.put("param_json", paramJson);
|
params.put("param_json", paramJson);
|
||||||
}
|
}
|
||||||
String logPayload = StringUtils.hasText(paramJson) ? PddOpenApiSupport.snippet(paramJson, 400) : "";
|
String logPayload = StringUtils.hasText(paramJson) ? PddOpenApiSupport.snippet(paramJson, 400) : "";
|
||||||
return postSignedAndLog(gatewayUrl, clientId, clientSecret, type, params, logPayload);
|
return postSignedAndLog(gatewayUrl, clientId, clientSecret, type, params, logPayload, Duration.ofSeconds(60));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -94,109 +93,27 @@ public class PddPopClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String logPayload = topLevelBizParams == null ? "" : PddOpenApiSupport.snippet(topLevelBizParams.toString(), 400);
|
String logPayload = topLevelBizParams == null ? "" : PddOpenApiSupport.snippet(topLevelBizParams.toString(), 400);
|
||||||
return postSignedAndLog(gatewayUrl, clientId, clientSecret, type, params, logPayload);
|
return postSignedAndLog(gatewayUrl, clientId, clientSecret, type, params, logPayload, Duration.ofSeconds(60));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 商品图片上传:{@code multipart/form-data},文本字段参与 MD5 签名,二进制字段不参与。
|
* {@code pdd.goods.image.upload}:与官方 curl/SDK 一致,{@code Content-Type: application/x-www-form-urlencoded},
|
||||||
*
|
* 表单字段含 {@code image}(图片字节的 Base64,无 {@code data:} 前缀)。
|
||||||
* @param apiType POP {@code type},如 {@code pdd.goods.image.upload}
|
|
||||||
* @param multipartFileField 文件 part 的 name,常见 {@code file}
|
|
||||||
*/
|
*/
|
||||||
public String invokeGoodsImgUpload(String gatewayUrl, String clientId, String clientSecret, String accessToken,
|
public String invokeGoodsImageUpload(String gatewayUrl, String clientId, String clientSecret, String accessToken,
|
||||||
byte[] fileBytes, String filename, String apiType, String multipartFileField) throws Exception {
|
byte[] imageBytes) throws Exception {
|
||||||
if (!StringUtils.hasText(gatewayUrl)) {
|
if (!StringUtils.hasText(gatewayUrl)) {
|
||||||
throw new IllegalArgumentException("gatewayUrl 不能为空");
|
throw new IllegalArgumentException("gatewayUrl 不能为空");
|
||||||
}
|
}
|
||||||
if (!StringUtils.hasText(apiType)) {
|
if (imageBytes == null || imageBytes.length == 0) {
|
||||||
throw new IllegalArgumentException("apiType 不能为空");
|
throw new IllegalArgumentException("image 不能为空");
|
||||||
}
|
}
|
||||||
if (fileBytes == null || fileBytes.length == 0) {
|
String b64 = Base64.getEncoder().encodeToString(imageBytes);
|
||||||
throw new IllegalArgumentException("file 不能为空");
|
Map<String, String> params = buildBaseParams(clientId, accessToken, "pdd.goods.image.upload", false);
|
||||||
}
|
params.put("image", b64);
|
||||||
String fileField = StringUtils.hasText(multipartFileField) ? multipartFileField.trim() : "file";
|
String logPayload = "pdd.goods.image.upload image=base64(len=" + b64.length() + ") rawBytes=" + imageBytes.length;
|
||||||
Map<String, String> params = buildBaseParams(clientId, accessToken, apiType, false);
|
return postSignedAndLog(gatewayUrl, clientId, clientSecret, "pdd.goods.image.upload", params, logPayload,
|
||||||
String sign = PddPopSignUtil.sign(params, clientSecret);
|
Duration.ofSeconds(180));
|
||||||
params.put("sign", sign);
|
|
||||||
|
|
||||||
String boundary = "----PddPopFormBoundary" + UUID.randomUUID().toString().replace("-", "");
|
|
||||||
String safeName = safeMultipartFilename(filename);
|
|
||||||
byte[] body = buildMultipartFormData(boundary, params, fileBytes, safeName, fileField);
|
|
||||||
|
|
||||||
HttpRequest request = HttpRequest.newBuilder()
|
|
||||||
.uri(URI.create(gatewayUrl))
|
|
||||||
.timeout(Duration.ofSeconds(120))
|
|
||||||
.header("Content-Type", "multipart/form-data; boundary=" + boundary)
|
|
||||||
.POST(HttpRequest.BodyPublishers.ofByteArray(body))
|
|
||||||
.build();
|
|
||||||
String host = safeHostForLog(gatewayUrl);
|
|
||||||
String clientMasked = PddSensitiveLogUtil.maskForLog(clientId);
|
|
||||||
long t0 = System.nanoTime();
|
|
||||||
try {
|
|
||||||
HttpResponse<String> resp = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
|
|
||||||
long durationMs = (System.nanoTime() - t0) / 1_000_000L;
|
|
||||||
int httpStatus = resp.statusCode();
|
|
||||||
String raw = resp.body();
|
|
||||||
boolean httpOk = httpStatus >= 200 && httpStatus < 300;
|
|
||||||
boolean popBizError = PddOpenApiSupport.isError(raw);
|
|
||||||
String snippet = PddOpenApiSupport.snippet(raw, 400);
|
|
||||||
if (!httpOk || popBizError) {
|
|
||||||
String errSummary = popBizError ? PddOpenApiSupport.formatError(raw) : "";
|
|
||||||
log.warn("PDD_POP api={} host={} clientId={} httpStatus={} durationMs={} bytes={} fileName={} fileField={} popBizError={} errSummary={} bodySnippet={}",
|
|
||||||
apiType, host, clientMasked, httpStatus, durationMs, fileBytes.length, safeName, fileField, popBizError, errSummary, snippet);
|
|
||||||
} else {
|
|
||||||
log.info("PDD_POP api={} host={} clientId={} httpStatus={} durationMs={} bytes={} fileName={} fileField={} bodySnippet={}",
|
|
||||||
apiType, host, clientMasked, httpStatus, durationMs, fileBytes.length, safeName, fileField, snippet);
|
|
||||||
}
|
|
||||||
return raw;
|
|
||||||
} catch (Exception e) {
|
|
||||||
long durationMs = (System.nanoTime() - t0) / 1_000_000L;
|
|
||||||
log.warn("PDD_POP api={} host={} clientId={} durationMs={} bytes={} invokeFailed={}",
|
|
||||||
apiType, host, clientMasked, durationMs, fileBytes.length, e.toString(), e);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String safeMultipartFilename(String filename) {
|
|
||||||
if (!StringUtils.hasText(filename)) {
|
|
||||||
return "image.jpg";
|
|
||||||
}
|
|
||||||
String t = filename.trim().replace("\"", "").replace("\r", "").replace("\n", "");
|
|
||||||
int slash = Math.max(t.lastIndexOf('/'), t.lastIndexOf('\\'));
|
|
||||||
if (slash >= 0) {
|
|
||||||
t = t.substring(slash + 1);
|
|
||||||
}
|
|
||||||
if (!StringUtils.hasText(t)) {
|
|
||||||
return "image.jpg";
|
|
||||||
}
|
|
||||||
return t.length() > 120 ? t.substring(t.length() - 120) : t;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] buildMultipartFormData(String boundary, Map<String, String> textFields, byte[] fileBytes,
|
|
||||||
String filename, String filePartName) throws Exception {
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(fileBytes.length + 2048);
|
|
||||||
String crlf = "\r\n";
|
|
||||||
byte[] crlfBytes = crlf.getBytes(StandardCharsets.UTF_8);
|
|
||||||
String fn = filename.replace("\"", "");
|
|
||||||
String part = (filePartName == null || filePartName.isBlank()) ? "file" : filePartName.replace("\"", "").trim();
|
|
||||||
for (Map.Entry<String, String> e : textFields.entrySet()) {
|
|
||||||
if (e.getKey() == null || e.getValue() == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String key = e.getKey().replace("\"", "");
|
|
||||||
baos.write(("--" + boundary + crlf).getBytes(StandardCharsets.UTF_8));
|
|
||||||
baos.write(("Content-Disposition: form-data; name=\"" + key + "\"" + crlf).getBytes(StandardCharsets.UTF_8));
|
|
||||||
baos.write(crlfBytes);
|
|
||||||
baos.write(e.getValue().getBytes(StandardCharsets.UTF_8));
|
|
||||||
baos.write(crlfBytes);
|
|
||||||
}
|
|
||||||
baos.write(("--" + boundary + crlf).getBytes(StandardCharsets.UTF_8));
|
|
||||||
baos.write(("Content-Disposition: form-data; name=\"" + part + "\"; filename=\"" + fn + "\"" + crlf).getBytes(StandardCharsets.UTF_8));
|
|
||||||
baos.write(("Content-Type: application/octet-stream" + crlf + crlf).getBytes(StandardCharsets.UTF_8));
|
|
||||||
baos.write(fileBytes);
|
|
||||||
baos.write(crlfBytes);
|
|
||||||
baos.write(("--" + boundary + "--" + crlf).getBytes(StandardCharsets.UTF_8));
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, String> buildBaseParams(String clientId, String accessToken, String type,
|
private static Map<String, String> buildBaseParams(String clientId, String accessToken, String type,
|
||||||
|
|
@ -217,14 +134,14 @@ public class PddPopClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String postSignedAndLog(String gatewayUrl, String clientId, String clientSecret, String type,
|
private String postSignedAndLog(String gatewayUrl, String clientId, String clientSecret, String type,
|
||||||
Map<String, String> params, String paramLogSnippet) throws Exception {
|
Map<String, String> params, String paramLogSnippet, Duration requestTimeout) throws Exception {
|
||||||
String sign = PddPopSignUtil.sign(params, clientSecret);
|
String sign = PddPopSignUtil.sign(params, clientSecret);
|
||||||
params.put("sign", sign);
|
params.put("sign", sign);
|
||||||
|
|
||||||
String body = formEncode(params);
|
String body = formEncode(params);
|
||||||
HttpRequest request = HttpRequest.newBuilder()
|
HttpRequest request = HttpRequest.newBuilder()
|
||||||
.uri(URI.create(gatewayUrl))
|
.uri(URI.create(gatewayUrl))
|
||||||
.timeout(Duration.ofSeconds(60))
|
.timeout(requestTimeout != null ? requestTimeout : Duration.ofSeconds(60))
|
||||||
.header("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8")
|
.header("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8")
|
||||||
.POST(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8))
|
.POST(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8))
|
||||||
.build();
|
.build();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue