使用 httpClient 和 Glassfish 提交 rest post 超时

Timeout submitting a rest post with httpClient and Glassfish

我有一个发送 json 对象和正文中的一组文件的 httpClient REST WS 是一个 glassfish (payara) 服务器 当文件很小(不超过 1k)时,它运行良好 当我发送一个文件比其他文件大的请求时(我尝试使用 ~130k 和 ~50k 文件),它会在以下函数 multipartStream.readBodyData(os); 处抛出错误

public static String parseMultipart(InputStream stream, List<UploadedFile> uploadedFiles) throws IOException {

    String msgInfo = null;

    MultipartStream multipartStream = new MultipartStream(stream, "".getBytes());
    boolean nextPart = multipartStream.skipPreamble();

    if (nextPart) {

        // Information
        multipartStream.readHeaders();

        ByteArrayOutputStream os = new ByteArrayOutputStream();
        multipartStream.readBodyData(os);
       //json part
        msgInfo = new String(os.toByteArray(), java.nio.charset.StandardCharsets.UTF_8);

        nextPart = multipartStream.readBoundary();
    }

    // Files
    while (nextPart) {

        String header = multipartStream.readHeaders();
        String fileName = null;

        int fileNameStart = header.indexOf("filename=\"");
        int fileNameEnd = -1;
        if (fileNameStart != -1) {

            fileNameEnd = header.indexOf("\"", fileNameStart + 10);
            if (fileNameEnd != -1) {
                fileName = header.substring(fileNameStart + 10, fileNameEnd);
            }
        }

        if (fileName != null) {

            // Reads the body - Actual file data
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            multipartStream.readBodyData(os);

            if (os.size() > 0) {
                UploadedFile uploadedFile = new ByteArrayUploadedFile(os.toByteArray(), fileName, "");
                uploadedFiles.add(uploadedFile);
            } else {

                return null;
            }

        } else {
            return null;
        }

        nextPart = multipartStream.readBoundary();
    }

    return msgInfo;

错误是

Warning:   StandardWrapperValve[webServices.ApplicationConfig]: Servlet.service() for servlet webServices.ApplicationConfig threw exception
java.util.concurrent.TimeoutException
    at org.glassfish.grizzly.nio.tmpselectors.TemporarySelectorReader.read(TemporarySelectorReader.java:126)
    at org.glassfish.grizzly.nio.tmpselectors.TemporarySelectorReader.read(TemporarySelectorReader.java:75)
    at org.glassfish.grizzly.AbstractReader.read(AbstractReader.java:72)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransportFilter.handleRead(TCPNIOTransportFilter.java:77)
    at org.glassfish.grizzly.filterchain.TransportFilter.handleRead(TransportFilter.java:173)
    at org.glassfish.grizzly.ssl.SSLBaseFilter$SSLTransportFilterWrapper.handleRead(SSLBaseFilter.java:1132)
    at org.glassfish.grizzly.filterchain.ExecutorResolver.execute(ExecutorResolver.java:119)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.read(DefaultFilterChain.java:352)
    at org.glassfish.grizzly.filterchain.FilterChainContext.read(FilterChainContext.java:736)
    at org.glassfish.grizzly.http.io.InputBuffer.blockingRead(InputBuffer.java:1103)
    at org.glassfish.grizzly.http.server.io.ServerInputBuffer.blockingRead(ServerInputBuffer.java:95)
    at org.glassfish.grizzly.http.io.InputBuffer.fill(InputBuffer.java:1127)
    at org.glassfish.grizzly.http.io.InputBuffer.read(InputBuffer.java:348)
    at org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:273)
    at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:270)
    at org.glassfish.jersey.message.internal.EntityInputStream.read(EntityInputStream.java:102)
    at myapp.webServices.MultipartStream.readBodyData(MultipartStream.java:333)
    ...

客户端部分是apache httpClient,相关部分是

    request = new HttpPost(baseUrl + wsName);
    MultipartEntityBuilder builder = MultipartEntityBuilder.create();
    builder.addTextBody("info", restBag.getAsJsonObject().toString(), ContentType.APPLICATION_JSON);

    for (File file : restBag.getFileMap().values()) {
        builder.addBinaryBody("file", file, ContentType.APPLICATION_OCTET_STREAM, file.getName());
    }
    HttpEntity multipart = builder.build();
    request.setEntity(multipart);
response = httpClient.execute(request, localContext);

更新

我尝试使用 apache commons 更改 REST 方法,但结果是一样的

@POST
@Path("/send")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON)
@RolesAllowed({"WS_Crea_Messaggio"})
public ReturnMessage sendMessage1(@Context HttpServletRequest httpRequest) throws IOException, JAXBException
{

    LOG.log(Level.FINEST, "User {0} called sendMessage", new Object[]{user});

    ReturnMessage ret = new ReturnMessage();
    String info = null;
    List<UploadedFile> uploadedFiles = new ArrayList<>();
    FileItemFactory factory = new DiskFileItemFactory();
    ServletFileUpload upload = new ServletFileUpload(factory);
// Parse the request
    Iterator /* FileItem */ items;
    try {
        items = upload.parseRequest(httpRequest).iterator();
while (items.hasNext()) {
    FileItem thisItem = (FileItem) items.next();
        if (thisItem.getFieldName().equals("info")) {
            info = thisItem.getString();
            // Do something with the value
    } else if (thisItem.getFieldName().equals("file")) {
        uploadedFiles.add(new ByteArrayUploadedFile(thisItem.get(), thisItem.getName(), thisItem.getContentType()));
    }

}
    }
    catch (FileUploadException ex) {
        LOG.log(Level.INFO, "Erroro uploading messages", ex);
        ret.setStatus(ReturnStatusEnum.ERROR);
        ret.setErrorCode(ReturnErrorCodeEnum.FILE_NOT_UPLOADED);
        return ret;
    }
....
}

运气不好,再次停止items = upload.parseRequest(httpRequest).iterator();等待超时

org.apache.commons.fileupload.FileUploadBase$IOFileUploadException: Processing of multipart/form-data request failed. java.util.concurrent.TimeoutException
at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:371)
at org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:126)
at myapp.webServices.MessagesWebService.sendMessage1(MessagesWebService.java:331)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1081)
at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:1153)
at com.sun.ejb.containers.BaseContainer.invokeBeanMethod(BaseContainer.java:4762)
at com.sun.ejb.EjbInvocation.invokeBeanMethod(EjbInvocation.java:656)
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:834)
at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:608)
at org.jboss.weld.ejb.AbstractEJBRequestScopeActivationInterceptor.aroundInvoke(AbstractEJBRequestScopeActivationInterceptor.java:64)
at org.jboss.weld.ejb.SessionBeanInterceptor.aroundInvoke(SessionBeanInterceptor.java:52)
at sun.reflect.GeneratedMethodAccessor147.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:895)
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:834)
at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:608)
at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doCall(SystemInterceptorProxy.java:163)
at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.aroundInvoke(SystemInterceptorProxy.java:140)
at sun.reflect.GeneratedMethodAccessor149.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:895)
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:834)
at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:374)
at com.sun.ejb.containers.BaseContainer.__intercept(BaseContainer.java:4734)
at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:4722)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:212)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:88)
at com.sun.proxy.$Proxy450.sendMessage1(Unknown Source)
at myapp.webServices.__EJB31_Generated__MessagesWebService__Intf____Bean__.sendMessage1(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory.invoke(ResourceMethodInvocationHandlerFactory.java:81)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.run(AbstractJavaResourceMethodDispatcher.java:144)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:205)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
at org.glassfish.jersey.server.ServerRuntime.run(ServerRuntime.java:326)
at org.glassfish.jersey.internal.Errors.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:473)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1693)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:318)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:416)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:283)
at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:466)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:169)
at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:206)
at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:180)
at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:235)
at org.glassfish.grizzly.filterchain.ExecutorResolver.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:133)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:526)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access0(WorkerThreadIOStrategy.java:56)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:593)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:573)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.IOException: java.util.concurrent.TimeoutException
at org.glassfish.grizzly.nio.transport.TCPNIOTransportFilter.handleRead(TCPNIOTransportFilter.java:90)
at org.glassfish.grizzly.filterchain.TransportFilter.handleRead(TransportFilter.java:173)
at org.glassfish.grizzly.ssl.SSLBaseFilter$SSLTransportFilterWrapper.handleRead(SSLBaseFilter.java:1132)
at org.glassfish.grizzly.filterchain.ExecutorResolver.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.read(DefaultFilterChain.java:352)
at org.glassfish.grizzly.filterchain.FilterChainContext.read(FilterChainContext.java:736)
at org.glassfish.grizzly.http.io.InputBuffer.blockingRead(InputBuffer.java:1103)
at org.glassfish.grizzly.http.server.io.ServerInputBuffer.blockingRead(ServerInputBuffer.java:95)
at org.glassfish.grizzly.http.io.InputBuffer.fill(InputBuffer.java:1127)
at org.glassfish.grizzly.http.io.InputBuffer.read(InputBuffer.java:348)
at org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:273)
at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:270)
at org.apache.commons.fileupload.MultipartStream$ItemInputStream.makeAvailable(MultipartStream.java:976)
at org.apache.commons.fileupload.MultipartStream$ItemInputStream.read(MultipartStream.java:886)
at java.io.InputStream.read(InputStream.java:101)
at org.apache.commons.fileupload.util.Streams.copy(Streams.java:96)
at org.apache.commons.fileupload.util.Streams.copy(Streams.java:66)
at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:366)
... 88 more
Caused by: java.util.concurrent.TimeoutException
at org.glassfish.grizzly.nio.tmpselectors.TemporarySelectorReader.read(TemporarySelectorReader.java:126)
at org.glassfish.grizzly.nio.tmpselectors.TemporarySelectorReader.read(TemporarySelectorReader.java:75)
at org.glassfish.grizzly.AbstractReader.read(AbstractReader.java:72)
at org.glassfish.grizzly.nio.transport.TCPNIOTransportFilter.handleRead(TCPNIOTransportFilter.java:77)
... 107 more

我已经在同一台机器上使用客户端和服务器对其进行了测试,但我也尝试过在同一子网上使用远程客户端

您得到的超时是因为底部的 NIO(非阻塞)层读取消息正文没有在超时内接收到新的数据块,默认情况下为 1 秒。这意味着服务器处理任何到达的东西,如果在 1 秒内没有更多的东西到达,它会抛出超时异常。

您可以将超时增加到 1 秒以上以处理更大的请求。您可以在管理控制台中的 Network Config -> Transports -> tcp -> Selector Poll Timeout 中执行此操作。默认情况下,它是 1000 毫秒。

原因可能是连接速度慢,比服务器读取数据的能力慢得多。对于较小的请求,我猜整个 1k 请求适合一个或少量 TCP 数据包,并且作为单个数据出现。对于更大的请求,数据包的数量更大,并且在很长的延迟之后才到达,可能是由于连接速度慢或 HTTP 客户端发送数据缓慢造成的。

问题与我使用的授权方法有关。 我正在使用客户端证书和基本身份验证访问应用程序 禁用证书部分,直到最后收到请求,没有问题 我将打开一个新问题来挖掘如何解决问题,因为我需要客户端证书身份验证