From c25001c5e46aba863fb9d7e1f68e818acece9ac1 Mon Sep 17 00:00:00 2001 From: redkale Date: Thu, 30 Nov 2023 15:40:09 +0800 Subject: [PATCH] =?UTF-8?q?HttpSimpleClient=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../redkale/cluster/HttpClusterRpcClient.java | 50 +++--- .../org/redkale/net/client/ClientCodec.java | 31 +--- .../redkale/net/client/ClientConnection.java | 1 + .../org/redkale/net/client/ClientRequest.java | 7 +- .../org/redkale/net/http/HttpRequest.java | 4 +- .../redkale/net/http/HttpSimpleClient.java | 24 ++- .../redkale/net/http/HttpSimpleRequest.java | 144 +++++++++++++----- .../org/redkale/net/sncp/SncpRequest.java | 3 +- .../test/http/HttpSimpleClientTest.java | 6 +- .../redkale/test/http/RequestCoderTest.java | 6 +- 10 files changed, 174 insertions(+), 102 deletions(-) diff --git a/src/main/java/org/redkale/cluster/HttpClusterRpcClient.java b/src/main/java/org/redkale/cluster/HttpClusterRpcClient.java index 3a11043f8..ba16150cb 100644 --- a/src/main/java/org/redkale/cluster/HttpClusterRpcClient.java +++ b/src/main/java/org/redkale/cluster/HttpClusterRpcClient.java @@ -123,6 +123,14 @@ public class HttpClusterRpcClient extends HttpRpcClient { clientHeaders.set(Rest.REST_HEADER_RESP_CONVERT, req.getRespConvertType().toString()); } + if (httpSimpleClient != null) { + HttpSimpleRequest newReq = req.copy().headers(clientHeaders); + InetSocketAddress addr = randomAddress(newReq, addrs); + if (logger.isLoggable(Level.FINEST)) { + logger.log(Level.FINEST, "httpAsync: module=" + localModule + ", resname=" + resname + ", addr=" + addr); + } + return (CompletableFuture) httpSimpleClient.sendAsync(addr, newReq); + } byte[] clientBody = null; if (isNotEmpty(req.getBody())) { String paramstr = req.getParametersToString(); @@ -147,7 +155,12 @@ public class HttpClusterRpcClient extends HttpRpcClient { }); } - private CompletableFuture> sendEachAddressAsync(HttpSimpleRequest req, + protected InetSocketAddress randomAddress(HttpSimpleRequest req, Set addrs) { + InetSocketAddress[] array = addrs.toArray(new InetSocketAddress[addrs.size()]); + return array[ThreadLocalRandom.current().nextInt(array.length)]; + } + + protected CompletableFuture> sendEachAddressAsync(HttpSimpleRequest req, String requestPath, final HttpHeaders clientHeaders, byte[] clientBody, Iterator it) { if (!it.hasNext()) { return new HttpResult().status(404).toFuture(); @@ -159,26 +172,21 @@ public class HttpClusterRpcClient extends HttpRpcClient { logger.log(Level.FINER, "sendEachAddressAsync: url: " + url + ", body: " + (clientBody != null ? new String(clientBody, StandardCharsets.UTF_8) : "") + ", headers: " + clientHeaders); } - if (httpSimpleClient != null) { - clientHeaders.set("Host", host); - return httpSimpleClient.postAsync(url, clientHeaders, clientBody); - } else { - java.net.http.HttpRequest.Builder builder = java.net.http.HttpRequest.newBuilder() - .uri(URI.create(url)) - .timeout(Duration.ofMillis(10_000)) - //存在sendHeader后不发送body数据的问题, java.net.http.HttpRequest的bug? - .method("POST", createBodyPublisher(clientBody)); - clientHeaders.forEach(builder::header); - return httpClient.sendAsync(builder.build(), java.net.http.HttpResponse.BodyHandlers.ofByteArray()) - .thenApply((java.net.http.HttpResponse resp) -> { - Traces.currentTraceid(req.getTraceid()); - final int rs = resp.statusCode(); - if (rs != 200) { - return new HttpResult().status(rs); - } - return new HttpResult<>(resp.body()); - }); - } + java.net.http.HttpRequest.Builder builder = java.net.http.HttpRequest.newBuilder() + .uri(URI.create(url)) + .timeout(Duration.ofMillis(10_000)) + //存在sendHeader后不发送body数据的问题, java.net.http.HttpRequest的bug? + .method("POST", createBodyPublisher(clientBody)); + clientHeaders.forEach(builder::header); + return httpClient.sendAsync(builder.build(), java.net.http.HttpResponse.BodyHandlers.ofByteArray()) + .thenApply((java.net.http.HttpResponse resp) -> { + Traces.currentTraceid(req.getTraceid()); + final int rs = resp.statusCode(); + if (rs != 200) { + return new HttpResult().status(rs); + } + return new HttpResult<>(resp.body()); + }); } private static java.net.http.HttpRequest.BodyPublisher createBodyPublisher(byte[] clientBody) { diff --git a/src/main/java/org/redkale/net/client/ClientCodec.java b/src/main/java/org/redkale/net/client/ClientCodec.java index 11b34789a..09d581a56 100644 --- a/src/main/java/org/redkale/net/client/ClientCodec.java +++ b/src/main/java/org/redkale/net/client/ClientCodec.java @@ -146,42 +146,25 @@ public abstract class ClientCodec { Traces.currentTraceid(request.traceid); respFuture.complete(rs); Traces.removeTraceid(); - } else { - workThread.runWork(() -> { - Traces.currentTraceid(request.traceid); - respFuture.complete(rs); - Traces.removeTraceid(); - }); - } + }); } else { //异常 - if (workThread.inIO() && workThread.getState() == Thread.State.RUNNABLE) { //fullCache时state不是RUNNABLE + workThread.runWork(() -> { Traces.currentTraceid(request.traceid); respFuture.completeExceptionally(exc); Traces.removeTraceid(); - } else { - workThread.runWork(() -> { - Traces.currentTraceid(request.traceid); - respFuture.completeExceptionally(exc); - Traces.removeTraceid(); - }); - } + }); } } catch (Throwable t) { - if (workThread.inIO() && workThread.getState() == Thread.State.RUNNABLE) { //fullCache时state不是RUNNABLE + workThread.runWork(() -> { Traces.currentTraceid(request.traceid); respFuture.completeExceptionally(t); Traces.removeTraceid(); - } else { - workThread.runWork(() -> { - Traces.currentTraceid(request.traceid); - respFuture.completeExceptionally(t); - Traces.removeTraceid(); - }); - } + }); connection.client.logger.log(Level.INFO, "Complete result error, request: " + respFuture.request, t); } } diff --git a/src/main/java/org/redkale/net/client/ClientConnection.java b/src/main/java/org/redkale/net/client/ClientConnection.java index 0a947a46e..d52b93a8d 100644 --- a/src/main/java/org/redkale/net/client/ClientConnection.java +++ b/src/main/java/org/redkale/net/client/ClientConnection.java @@ -312,6 +312,7 @@ public abstract class ClientConnection { this.readState = READ_STATE_HEADER; } if (this.readState == READ_STATE_HEADER) { - this.completed = true; if (last != null && ((HttpRequest) last).headerLength > 0) { final HttpRequest httplast = (HttpRequest) last; int bufremain = buffer.remaining(); @@ -351,9 +350,10 @@ public class HttpRequest extends Request { this.boundary = true; } if (this.boundary) { - this.completed = false; //completed=true时ProtocolCodec会继续读下一个request this.keepAlive = false; //文件上传必须设置keepAlive为false,因为文件过大时用户不一定会skip掉多余的数据 } + //completed=true时ProtocolCodec会继续读下一个request + this.completed = !this.boundary && !maybews && this.headerParsed; this.readState = READ_STATE_BODY; } if (this.readState == READ_STATE_BODY) { diff --git a/src/main/java/org/redkale/net/http/HttpSimpleClient.java b/src/main/java/org/redkale/net/http/HttpSimpleClient.java index bdb5ae61e..7230afc8b 100644 --- a/src/main/java/org/redkale/net/http/HttpSimpleClient.java +++ b/src/main/java/org/redkale/net/http/HttpSimpleClient.java @@ -240,10 +240,25 @@ public class HttpSimpleClient extends Client 0 ? uri.getPort() : (url.startsWith("https:") ? 443 : 80); int urlpos = url.indexOf("/", url.indexOf("//") + 3); - array.put((method.toUpperCase() + " " + (urlpos > 0 ? url.substring(urlpos) : "/") + " HTTP/1.1\r\n").getBytes(StandardCharsets.UTF_8)); + final String path = (urlpos > 0 ? url.substring(urlpos) : "/"); + if (!url.startsWith("https:")) { + HttpSimpleRequest req = HttpSimpleRequest.createPath(path, headers).method(method).body(body); + return (CompletableFuture) sendAsync(new InetSocketAddress(host, port), req) + .thenApply((HttpSimpleResult rs) -> { + if (valueType == null) { + return rs; + } else { + Convert c = convert == null ? JsonConvert.root() : convert; + return rs.result(c.convertToBytes(valueType, (byte[]) rs.result)); + } + }); + } + + //以下代码暂废弃 + final ByteArray array = new ByteArray(); + array.put((method.toUpperCase() + " " + path + " HTTP/1.1\r\n").getBytes(StandardCharsets.UTF_8)); array.put(("Host: " + uri.getHost() + "\r\n").getBytes(StandardCharsets.UTF_8)); array.put(HttpSimpleRequest.contentLengthBytes(body)); @@ -263,7 +278,6 @@ public class HttpSimpleClient extends Client 0 ? uri.getPort() : (url.startsWith("https:") ? 443 : 80); return createConnection(host, port).thenCompose(conn -> { Traces.currentTraceid(traceid); final CompletableFuture> future = new CompletableFuture(); @@ -304,7 +318,7 @@ public class HttpSimpleClient extends Client copyFunc = Copier.func(HttpSimpleRequest.class, HttpSimpleRequest.class); + + @ConvertColumn(index = 12) @Comment("是否RPC请求, 该类通常是为RPC创建的,故默认是true") protected boolean rpc = true; - @ConvertColumn(index = 3) + @ConvertColumn(index = 13) @Comment("链路ID") protected String traceid; - @ConvertColumn(index = 4) + @ConvertColumn(index = 14) @Comment("请求参数的ConvertType") protected ConvertType reqConvertType; - @ConvertColumn(index = 5) + @ConvertColumn(index = 15) @Comment("输出结果的ConvertType") protected ConvertType respConvertType; @Comment("Method GET/POST/...") - @ConvertColumn(index = 6) + @ConvertColumn(index = 16) protected String method; - @ConvertColumn(index = 7) + @ConvertColumn(index = 17) @Comment("请求的Path") protected String path; - @ConvertColumn(index = 8) + @ConvertColumn(index = 18) @Comment("请求的前缀") protected String contextPath; - @ConvertColumn(index = 9) + @ConvertColumn(index = 19) @Comment("客户端IP") protected String remoteAddr; - @ConvertColumn(index = 10) + @ConvertColumn(index = 20) @Comment("Locale国际化") protected String locale; - @ConvertColumn(index = 11) + @ConvertColumn(index = 21) @Comment("会话ID") protected String sessionid; - @ConvertColumn(index = 12) + @ConvertColumn(index = 22) @Comment("Content-Type") protected String contentType; - @ConvertColumn(index = 13) //@since 2.5.0 由int改成Serializable, 具体数据类型只能是int、long、BigInteger、String + @ConvertColumn(index = 23) //@since 2.5.0 由int改成Serializable, 具体数据类型只能是int、long、BigInteger、String protected Serializable currentUserid; - @ConvertColumn(index = 14) + @ConvertColumn(index = 24) @Comment("http header信息") protected HttpHeaders headers; - @ConvertColumn(index = 15) + @ConvertColumn(index = 25) @Comment("参数信息") protected HttpParameters params; - @ConvertColumn(index = 16) + @ConvertColumn(index = 26) @Comment("http body信息") protected byte[] body; //对应HttpRequest.array public static HttpSimpleRequest createPath(String path) { - return new HttpSimpleRequest().path(path).method("POST").traceid(Traces.currentTraceid()); + return new HttpSimpleRequest().path(path).traceid(Traces.currentTraceid()); + } + + public static HttpSimpleRequest createPath(String path, HttpHeaders header) { + return createPath(path).headers(header); } public static HttpSimpleRequest createPath(String path, Object... params) { - HttpSimpleRequest req = new HttpSimpleRequest().path(path).method("POST").traceid(Traces.currentTraceid()); - int len = params.length / 2; - for (int i = 0; i < len; i++) { - req.param(params[i * 2].toString(), params[i * 2 + 1]); + return createPath(path, (HttpHeaders) null, params); + } + + public static HttpSimpleRequest createPath(String path, HttpHeaders header, Object... params) { + HttpSimpleRequest req = createPath(path).headers(header); + if (params.length > 0) { + int len = params.length / 2; + for (int i = 0; i < len; i++) { + req.param(params[i * 2].toString(), params[i * 2 + 1]); + } } return req; } - public static HttpSimpleRequest createPath(String path, HttpHeaders header) { - return new HttpSimpleRequest().path(path).method("POST").headers(header).traceid(Traces.currentTraceid()); + public static HttpSimpleRequest createGetPath(String path) { + return createPath(path).method("GET"); + } + + public static HttpSimpleRequest createGetPath(String path, HttpHeaders header) { + return createPath(path, header).method("GET"); + } + + public static HttpSimpleRequest createGetPath(String path, Object... params) { + return createPath(path, params).method("GET"); + } + + public static HttpSimpleRequest createGetPath(String path, HttpHeaders header, Object... params) { + return createPath(path, header, params).method("GET"); + } + + public static HttpSimpleRequest createPostPath(String path) { + return createPath(path).method("POST"); + } + + public static HttpSimpleRequest createPostPath(String path, HttpHeaders header) { + return createPath(path, header).method("POST"); + } + + public static HttpSimpleRequest createPostPath(String path, Object... params) { + return createPath(path, params).method("POST"); + } + + public static HttpSimpleRequest createPostPath(String path, HttpHeaders header, Object... params) { + return createPath(path, header, params).method("POST"); + } + + public HttpSimpleRequest copy() { + HttpSimpleRequest rs = copyFunc.apply(this); + rs.workThread = this.workThread; + rs.createTime = this.createTime; + return rs; } @Override public void writeTo(ClientConnection conn, ByteArray array) { //组装path和body String requestPath = requestPath(); - String contentType0 = this.contentType; + String contentType0 = Utility.orElse(this.contentType, "x-www-form-urlencoded"); byte[] clientBody = null; if (isNotEmpty(body)) { String paramstr = getParametersToString(); @@ -133,11 +183,14 @@ public class HttpSimpleRequest extends ClientRequest implements java.io.Serializ contentType0 = "x-www-form-urlencoded"; } //写status - array.put((method.toUpperCase() + " " + requestPath + " HTTP/1.1\r\n").getBytes(StandardCharsets.UTF_8)); + array.put(((method == null ? "GET" : method.toUpperCase()) + " " + requestPath + " HTTP/1.1\r\n").getBytes(StandardCharsets.UTF_8)); //写header if (traceid != null && !containsHeaderIgnoreCase(Rest.REST_HEADER_TRACEID)) { array.put((Rest.REST_HEADER_TRACEID + ": " + traceid + "\r\n").getBytes(StandardCharsets.UTF_8)); } + if (currentUserid != null && !containsHeaderIgnoreCase(Rest.REST_HEADER_CURRUSERID)) { + array.put((Rest.REST_HEADER_CURRUSERID + ": " + currentUserid + "\r\n").getBytes(StandardCharsets.UTF_8)); + } if (!containsHeaderIgnoreCase("User-Agent")) { array.put(header_bytes_useragent); } @@ -215,16 +268,20 @@ public class HttpSimpleRequest extends ClientRequest implements java.io.Serializ } public HttpSimpleRequest path(String path) { - if (path.indexOf(' ') >= 0 || path.indexOf('\r') >= 0 || path.indexOf('\n') >= 0) { - throw new RedkaleException("http-path(" + path + ") is illegal"); + if (path != null) { + if (path.indexOf(' ') >= 0 || path.indexOf('\r') >= 0 || path.indexOf('\n') >= 0) { + throw new RedkaleException("http-path(" + path + ") is illegal"); + } } this.path = path; return this; } public HttpSimpleRequest contextPath(String contextPath) { - if (contextPath.indexOf(' ') >= 0 || contextPath.indexOf('\r') >= 0 || contextPath.indexOf('\n') >= 0) { - throw new RedkaleException("http-context-path(" + contextPath + ") is illegal"); + if (contextPath != null) { + if (contextPath.indexOf(' ') >= 0 || contextPath.indexOf('\r') >= 0 || contextPath.indexOf('\n') >= 0) { + throw new RedkaleException("http-context-path(" + contextPath + ") is illegal"); + } } this.contextPath = contextPath; return this; @@ -296,6 +353,11 @@ public class HttpSimpleRequest extends ClientRequest implements java.io.Serializ } public HttpSimpleRequest method(String method) { + if (method != null) { + if (method.indexOf(' ') >= 0 || method.indexOf('\r') >= 0 || method.indexOf('\n') >= 0) { + throw new RedkaleException("http-method(" + method + ") is illegal"); + } + } this.method = method; return this; } @@ -419,7 +481,7 @@ public class HttpSimpleRequest extends ClientRequest implements java.io.Serializ } public void setRpc(boolean rpc) { - this.rpc = rpc; + rpc(rpc); } public String getTraceid() { @@ -427,7 +489,7 @@ public class HttpSimpleRequest extends ClientRequest implements java.io.Serializ } public void setTraceid(String traceid) { - this.traceid = traceid; + traceid(traceid); } public String getMethod() { @@ -435,7 +497,7 @@ public class HttpSimpleRequest extends ClientRequest implements java.io.Serializ } public void setMethod(String method) { - this.method = method; + method(method); } public String getPath() { @@ -443,7 +505,7 @@ public class HttpSimpleRequest extends ClientRequest implements java.io.Serializ } public void setPath(String path) { - this.path = path; + path(path); } public String getContextPath() { @@ -451,7 +513,7 @@ public class HttpSimpleRequest extends ClientRequest implements java.io.Serializ } public void setContextPath(String contextPath) { - this.contextPath = contextPath; + contextPath(contextPath); } public String getSessionid() { @@ -459,7 +521,7 @@ public class HttpSimpleRequest extends ClientRequest implements java.io.Serializ } public void setSessionid(String sessionid) { - this.sessionid = sessionid; + sessionid(sessionid); } public String getRemoteAddr() { @@ -467,7 +529,7 @@ public class HttpSimpleRequest extends ClientRequest implements java.io.Serializ } public void setRemoteAddr(String remoteAddr) { - this.remoteAddr = remoteAddr; + remoteAddr(remoteAddr); } public String getLocale() { @@ -475,7 +537,7 @@ public class HttpSimpleRequest extends ClientRequest implements java.io.Serializ } public void setLocale(String locale) { - this.locale = locale; + locale(locale); } public Serializable getCurrentUserid() { @@ -483,7 +545,7 @@ public class HttpSimpleRequest extends ClientRequest implements java.io.Serializ } public void setCurrentUserid(Serializable currentUserid) { - this.currentUserid = currentUserid; + currentUserid(currentUserid); } public String getContentType() { @@ -491,7 +553,7 @@ public class HttpSimpleRequest extends ClientRequest implements java.io.Serializ } public void setContentType(String contentType) { - this.contentType = contentType; + contentType(contentType); } public HttpHeaders getHeaders() { @@ -515,7 +577,7 @@ public class HttpSimpleRequest extends ClientRequest implements java.io.Serializ } public void setBody(byte[] body) { - this.body = body; + body(body); } public ConvertType getReqConvertType() { @@ -523,7 +585,7 @@ public class HttpSimpleRequest extends ClientRequest implements java.io.Serializ } public void setReqConvertType(ConvertType reqConvertType) { - this.reqConvertType = reqConvertType; + reqConvertType(reqConvertType); } public ConvertType getRespConvertType() { @@ -531,7 +593,7 @@ public class HttpSimpleRequest extends ClientRequest implements java.io.Serializ } public void setRespConvertType(ConvertType respConvertType) { - this.respConvertType = respConvertType; + respConvertType(respConvertType); } @Override diff --git a/src/main/java/org/redkale/net/sncp/SncpRequest.java b/src/main/java/org/redkale/net/sncp/SncpRequest.java index 061627967..4028bb721 100644 --- a/src/main/java/org/redkale/net/sncp/SncpRequest.java +++ b/src/main/java/org/redkale/net/sncp/SncpRequest.java @@ -83,7 +83,6 @@ public class SncpRequest extends Request { } //---------------------head---------------------------------- if (this.readState == READ_STATE_HEADER) { - this.completed = true; int remain = buffer.remaining(); int expect = halfArray == null ? this.headerSize - 2 : this.headerSize - 2 - halfArray.length(); if (remain < expect) { @@ -110,6 +109,8 @@ public class SncpRequest extends Request { return -1; } this.traceid = this.header.getTraceid(); + //completed=true时ProtocolCodec会继续读下一个request + this.completed = true; this.readState = READ_STATE_BODY; } //---------------------body---------------------------------- diff --git a/src/test/java/org/redkale/test/http/HttpSimpleClientTest.java b/src/test/java/org/redkale/test/http/HttpSimpleClientTest.java index 35e8debb0..a902df067 100644 --- a/src/test/java/org/redkale/test/http/HttpSimpleClientTest.java +++ b/src/test/java/org/redkale/test/http/HttpSimpleClientTest.java @@ -46,7 +46,7 @@ public class HttpSimpleClientTest { HttpSimpleClient client = HttpSimpleClient.create(asyncGroup); InetSocketAddress addr = new InetSocketAddress("127.0.0.1", port); { - HttpSimpleRequest req = HttpSimpleRequest.createPath("/test").param("id", 100); + HttpSimpleRequest req = HttpSimpleRequest.createPostPath("/test").param("id", 100); System.out.println(client.getAsync("http://127.0.0.1:" + port + req.getPath() + "?id=100").join()); System.out.println(client.sendAsync(addr, req).join()); } @@ -55,7 +55,7 @@ public class HttpSimpleClientTest { final CountDownLatch cdl = new CountDownLatch(count); for (int i = 100; i < 100 + count; i++) { final int index = i; - HttpSimpleRequest req = HttpSimpleRequest.createPath("/test").param("id", index); + HttpSimpleRequest req = HttpSimpleRequest.createPostPath("/test").param("id", index); client.getAsync("http://127.0.0.1:" + port + req.getPath() + "?id=" + index).whenComplete((v, t) -> { cdl.countDown(); Assertions.assertEquals("ok-" + index, new String((byte[]) v.getResult())); @@ -68,7 +68,7 @@ public class HttpSimpleClientTest { final CountDownLatch cdl = new CountDownLatch(count); for (int i = 100; i < 100 + count; i++) { final int index = i; - HttpSimpleRequest req = HttpSimpleRequest.createPath("/test").param("id", index); + HttpSimpleRequest req = HttpSimpleRequest.createPostPath("/test").param("id", index); client.sendAsync(addr, req).whenComplete((v, t) -> { cdl.countDown(); System.out.println("输出: " + new String((byte[]) v.getResult())); diff --git a/src/test/java/org/redkale/test/http/RequestCoderTest.java b/src/test/java/org/redkale/test/http/RequestCoderTest.java index 659433171..42a5703d4 100644 --- a/src/test/java/org/redkale/test/http/RequestCoderTest.java +++ b/src/test/java/org/redkale/test/http/RequestCoderTest.java @@ -28,7 +28,7 @@ public class RequestCoderTest { @Test public void run1() throws Exception { - HttpSimpleRequest req1 = HttpSimpleRequest.createPath("/aaa"); + HttpSimpleRequest req1 = HttpSimpleRequest.createPostPath("/aaa"); System.out.println("simpleRequest1: " + req1); byte[] bytes = HttpSimpleRequestCoder.getInstance().encode(req1); HttpSimpleRequest req2 = HttpSimpleRequestCoder.getInstance().decode(bytes); @@ -41,7 +41,7 @@ public class RequestCoderTest { @Test public void run2() throws Exception { - HttpSimpleRequest req1 = HttpSimpleRequest.createPath("/aaa"); + HttpSimpleRequest req1 = HttpSimpleRequest.createPostPath("/aaa"); req1.addHeader("X-aaa", "aaa"); req1.param("bean", "{}"); System.out.println("simpleRequest1: " + req1); @@ -56,7 +56,7 @@ public class RequestCoderTest { @Test public void run3() throws Exception { - HttpSimpleRequest req1 = HttpSimpleRequest.createPath("/aaa"); + HttpSimpleRequest req1 = HttpSimpleRequest.createPostPath("/aaa"); req1.addHeader("X-aaa", "aaa"); req1.addHeader("X-bbb", "bbb1"); req1.addHeader("X-bbb", "bbb2");