SWA响应的Java传输作为具有大附件的HttpEntity失败(无法分组多部分)

时间:2017-05-30 16:16:16

标签: soap server multipart apache-httpcomponents chunked-encoding

请注意:此问题也已发布到Apache HttpClient官方用户邮件列表中。

问题

基于Apache HttpComponents构建的基于Java的服务器应如何组装并发送带有附件(SWA)响应的大型SOAP?

问题详情

Apache HttpClient Java API不支持分块多部分HttpEntity实例。当SWA响应中的附件很大(> 2 MiB)时,向模拟服务器发出SOAP请求的客户端(特别是基于Apache的Java客户端正在抛出org.apache.http.NoHttpResponseExceptions)失败。传输小附件时不会出现任何例外情况。 HTTP Content-Length标头是正确的。

用例

能够传输任意内容长度的SWA响应的多线程SOAP服务器

平台

Java 8 64b

必需的图书馆

HttpCore v4.4.6 + HttpMime v4.5.3

错误复制

  1. 使用HttpCore v4.4.6和HttpMime v4.5.3库构建示例源代码(HttpMime是HttpClient项目的一部分)。
  2. 以足够大(> 2 MiB)" random.png.gz"运行程序。二进制文件。
  3. 通过某个第三方客户端向服务器发送任意HTTP POST请求。由于它是具有精确日志记录的基于Apache的Java客户端,因此建议使用SoapUI。 NB:无法接收服务器生成的大型多部分结果。
  4. 示例服务器来源

    import java.io.File;
    import java.io.IOException;
    import java.nio.file.Files;
    import java.util.Locale;
    import java.util.concurrent.TimeUnit;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import org.apache.http.ExceptionLogger;
    import org.apache.http.HttpEntity;
    import org.apache.http.HttpException;
    import org.apache.http.HttpRequest;
    import org.apache.http.HttpResponse;
    import static org.apache.http.HttpStatus.SC_OK;
    import org.apache.http.MethodNotSupportedException;
    import org.apache.http.entity.ContentType;
    import org.apache.http.entity.mime.MultipartEntityBuilder;
    import org.apache.http.entity.mime.content.ByteArrayBody;
    import org.apache.http.entity.mime.content.StringBody;
    import org.apache.http.impl.nio.bootstrap.HttpServer;
    import org.apache.http.impl.nio.bootstrap.ServerBootstrap;
    import org.apache.http.impl.nio.reactor.IOReactorConfig;
    import org.apache.http.nio.protocol.BasicAsyncRequestConsumer;
    import org.apache.http.nio.protocol.BasicAsyncResponseProducer;
    import org.apache.http.nio.protocol.HttpAsyncExchange;
    import org.apache.http.nio.protocol.HttpAsyncRequestConsumer;
    import org.apache.http.nio.protocol.HttpAsyncRequestHandler;
    import org.apache.http.protocol.HttpContext;
    
    public class HttpComponentsConciseTest {
    
        /* 
         * The random.png.gz file must be large (> 2 MiB)
         */
        private static final String LARGE_COMPRESSED_FILE_NAME = "random.png.gz";
        private static final File LARGE_TEST_GZIP_FILE = new File(LARGE_COMPRESSED_FILE_NAME);
        private static final String SOAP_RESPONSE_MESSAGE_XML
                = "<soapenv:Envelope "
                + "xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
                + "   <soapenv:Header/>\n"
                + "   <soapenv:Body>\n"
                + "      <AResponse>\n"
                + "         <ResponseFile>" + LARGE_COMPRESSED_FILE_NAME + "</ResponseFile>\n"
                + "      </AResponse>\n"
                + "   </soapenv:Body>\n"
                + "</soapenv:Envelope>";
    
        private static final int PORT_NUMBER = 8080;
    
        public static void main(String[] args) {
            startHttpServer();
        }
    
        private static void startHttpServer() {
            IOReactorConfig config = IOReactorConfig.custom()
                    .setIoThreadCount(1)
                    .setSoTimeout(15000)
                    .setTcpNoDelay(true)
                    .build();
    
            final HttpServer server = ServerBootstrap.bootstrap()
                    .setListenerPort(PORT_NUMBER)
                    .setServerInfo("Test/1.1")
                    .setIOReactorConfig(config)
                    .setExceptionLogger(ExceptionLogger.STD_ERR)
                    .registerHandler("*", new PrimaryRequestHandler())
                    .create();
    
            Runtime.getRuntime().addShutdownHook(new Thread(() -> server.shutdown(5,
                    TimeUnit.MILLISECONDS)));
    
            Thread serverOwner = new Thread(() -> {
    
                try {
                    server.start();
                } catch (IOException ex) {
                    Logger.getLogger(HttpComponentsConciseTest.class.getName()).log(Level.SEVERE, null,
                            ex);
                }
            }, "ServerOwner");
            serverOwner.start();
        }
    
        private static class PrimaryRequestHandler implements HttpAsyncRequestHandler<HttpRequest> {
    
            @Override
            public HttpAsyncRequestConsumer<HttpRequest> processRequest(
                    final HttpRequest request,
                    final HttpContext context) {
                return new BasicAsyncRequestConsumer();
            }
    
            @Override
            public void handle(
                    final HttpRequest request,
                    final HttpAsyncExchange httpexchange,
                    final HttpContext context) throws HttpException, IOException {
                HttpResponse response = httpexchange.getResponse();
    
                String method = request.getRequestLine().getMethod().toUpperCase(Locale.ENGLISH);
                if (!method.equals("POST")) {
                    throw new MethodNotSupportedException(method + " method not supported");
                }
    
                StringBody soapResponseStringBody = new StringBody(SOAP_RESPONSE_MESSAGE_XML,
                        ContentType.APPLICATION_XML);
                FileBody soapAttachment = new FileBody(LARGE_TEST_GZIP_FILE);
                HttpEntity responseEntity = MultipartEntityBuilder.create()
                        .addPart("SOAP Envelope", soapResponseStringBody)
                        .addPart(LARGE_COMPRESSED_FILE_NAME, soapAttachment)
                        .build();
                response.setStatusCode(SC_OK);
                response.setEntity(responseEntity);
    
                httpexchange.submitResponse(new BasicAsyncResponseProducer(response));
            }
        }
    }
    

    粘贴到源的链接

    https://pastebin.com/2Hzdhpt3

0 个答案:

没有答案