IOException: Transmisión cerrada al subir archivos al servidor

Mi aplicación está lanzando este error al intentar subir cualquier archivo:

java.io.IOException: Stream closed
        at java.base/java.io.PushbackInputStream.ensureOpen(PushbackInputStream.java:75)
        at java.base/java.io.PushbackInputStream.read(PushbackInputStream.java:163)
        at java.base/java.io.FilterInputStream.read(FilterInputStream.java:107)
        at com.google.common.io.ByteStreams.copy(ByteStreams.java:70)
        at com.google.common.io.ByteStreams.toByteArray(ByteStreams.java:115)
        at com.mycompany.backend.resource.impl.FileServerResource.createFile(FileServerResource.java:120)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.restlet.resource.ServerResource.doHandle(ServerResource.java:508)
        at org.restlet.resource.ServerResource.post(ServerResource.java:1341)
        at org.restlet.resource.ServerResource.doHandle(ServerResource.java:606)
        at org.restlet.resource.ServerResource.doNegotiatedHandle(ServerResource.java:662)
        at org.restlet.resource.ServerResource.doConditionalHandle(ServerResource.java:348)
        at org.restlet.resource.ServerResource.handle(ServerResource.java:1020)
        at org.restlet.resource.Finder.handle(Finder.java:236)
        at org.restlet.routing.Filter.doHandle(Filter.java:150)
        at org.restlet.routing.Filter.handle(Filter.java:197)
        at org.restlet.routing.Router.doHandle(Router.java:422)
        at org.restlet.routing.Router.handle(Router.java:641)
        at org.restlet.routing.Filter.doHandle(Filter.java:150)
        at org.restlet.routing.Filter.handle(Filter.java:197)
        at org.restlet.routing.Filter.doHandle(Filter.java:150)
        at org.restlet.routing.Filter.handle(Filter.java:197)
        at org.restlet.routing.Filter.doHandle(Filter.java:150)
        at org.restlet.routing.Filter.handle(Filter.java:197)
        at org.restlet.routing.Filter.doHandle(Filter.java:150)
        at org.restlet.routing.Filter.handle(Filter.java:197)
        at org.restlet.routing.Filter.doHandle(Filter.java:150)
        at org.restlet.routing.Filter.handle(Filter.java:197)
        at org.restlet.routing.Filter.doHandle(Filter.java:150)
        at org.restlet.engine.application.StatusFilter.doHandle(StatusFilter.java:140)
        at org.restlet.routing.Filter.handle(Filter.java:197)
        at org.restlet.routing.Filter.doHandle(Filter.java:150)
        at org.restlet.routing.Filter.handle(Filter.java:197)
        at org.restlet.engine.CompositeHelper.handle(CompositeHelper.java:202)
        at org.restlet.engine.application.ApplicationHelper.handle(ApplicationHelper.java:77)
        at org.restlet.Application.handle(Application.java:385)
        at org.restlet.routing.Filter.doHandle(Filter.java:150)
        at org.restlet.routing.Filter.handle(Filter.java:197)
        at org.restlet.routing.Router.doHandle(Router.java:422)
        at org.restlet.routing.Router.handle(Router.java:641)
        at org.restlet.routing.Filter.doHandle(Filter.java:150)
        at org.restlet.routing.Filter.handle(Filter.java:197)
        at org.restlet.routing.Router.doHandle(Router.java:422)
        at org.restlet.routing.Router.handle(Router.java:641)
        at org.restlet.routing.Filter.doHandle(Filter.java:150)
        at org.restlet.routing.Filter.handle(Filter.java:197)
        at org.restlet.engine.CompositeHelper.handle(CompositeHelper.java:202)
        at org.restlet.Component.handle(Component.java:408)
        at org.restlet.Server.handle(Server.java:507)
        at org.restlet.engine.connector.ServerHelper.handle(ServerHelper.java:63)
        at org.restlet.engine.adapter.HttpServerHelper.handle(HttpServerHelper.java:143)
        at org.restlet.ext.servlet.ServerServlet.service(ServerServlet.java:1117)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
        at nginx.unit.Context$ServletReg.service(Context.java:2011)
        at nginx.unit.Context$CtxFilterChain.doFilter(Context.java:750)
        at nginx.unit.Context.service(Context.java:971)

El problema está bastante aislado y sólo ocurre en el servidor remoto con NGINX + NGINX Unit server. Correr en localhost / jetty incrustado durante el desarrollo no arroja este error.

El código Java que lanza este error:

@Override
public File createFile(Representation entity) {
      if (entity != null
          && MediaType.APPLICATION_OCTET_STREAM.equals(entity.getMediaType())) {
        InputStream inputStream = entity.getStream(); // <--- error thrown here
        File file = fileRepository.put(destinationFile, inputStream);
        setStatus(Status.SUCCESS_CREATED);
        return file;
      }
}

¿Cómo puedo depurar esto desde el servidor NGINX y en la aplicación Java también? ¿Cómo puedo encontrar lo que está cerrando el flujo prematuramente?

Pregunta hecha hace 3 años, 5 meses, 4 días - Por techwizkid


3 Respuestas:

  • Este problema sucede cuando NGINX proxy_pass cierra la conexión para resolver esto, haz algo como:

    server { 
      location / { 
        proxy_pass http://upstream; 
        proxy_set_header Connection ""; 
        proxy_http_version 1.1; 
      } 
    }
    

    Establecer el proxy_set_header Connection ""

    Respondida el Dec 18, 2020 a las 16:35 - por apiartisan

    Votos positivos: 0 | Votos negativos: 0

  • El error "java.io.IOException: Stream closed" indica que se está intentando leer de un flujo de entrada que ya ha sido cerrado. En tu código, el error se produce en la línea donde intentas obtener el flujo de entrada desde la representación recibida en la petición.

    Para depurar este error desde el servidor NGINX, puedes revisar los logs de NGINX para ver si hay algún error específico relacionado con la transmisión de archivos. También puedes verificar la configuración de NGINX para asegurarte de que no haya ninguna restricción o límite en el tamaño de los archivos que se pueden subir.

    Desde la aplicación Java, puedes intentar atrapar la excepción IOException y loguear más información sobre el estado del flujo de entrada en ese momento para tratar de entender por qué se cerró prematuramente. Por ejemplo:

    java
    @Override
    public File createFile(Representation entity) {
        if (entity != null
                && MediaType.APPLICATION_OCTET_STREAM.equals(entity.getMediaType())) {
            try {
                InputStream inputStream = entity.getStream();
                File file = fileRepository.put(destinationFile, inputStream);
                setStatus(Status.SUCCESS_CREATED);
                return file;
            } catch (IOException e) {
                // Log the exception and any additional information that may help identify the issue
                e.printStackTrace();
                // You can also log the entity and any other relevant data for debugging
                System.out.println("Entity: " + entity);
                throw new RuntimeException("Error creating file", e);
            }
        }
    }
    

    Además, te sugiero considerar algunas buenas prácticas al trabajar con flujos de entrada en Java, como siempre cerrar los flujos correctamente al final de su uso o utilizar try-with-resources para gestionar la apertura y cierre de los flujos automáticamente.

    Espero que esta información te sea útil para resolver el problema con la transmisión de archivos en tu aplicación. ¡Déjame saber si necesitas más ayuda!

    Respondida el Dec 19, 2020 a las 16:33 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Depuración desde el servidor NGINX

    Verifica los registros de NGINX y NGINX Unit server para detectar cualquier error o mensaje relacionado con el cierre del flujo. Habilita la depuración en el servidor NGINX y NGINX Unit para obtener más información sobre el proceso de solicitud. Usa herramientas como ngxtop o ngx_top para monitorear el uso de recursos y detectar cualquier problema relacionado con el cierre de flujos.

    Depuración desde la aplicación Java

    Utiliza herramientas de depuración como un depurador de Java (por ejemplo, IntelliJ IDEA o Eclipse) para establecer puntos de interrupción en el código Java que maneja la subida de archivos. Examina las excepciones arrojadas e imprime mensajes de registro para identificar dónde y cuándo se cierra el flujo. Revisa el código de gestión de flujos para detectar cualquier error o condición que pueda provocar el cierre del flujo.

    Posibles causas del cierre del flujo

    Tamaño máximo de solicitud excedido: Verifica la configuración del servidor Web y del servidor de aplicaciones para asegurarte de que el tamaño máximo de solicitud es lo suficientemente grande para manejar subidas de archivos. Tiempo de espera de solicitud agotado: Aumenta el tiempo de espera de solicitud en la configuración del servidor Web y del servidor de aplicaciones para evitar que las solicitudes se agoten antes de que se completen las subidas de archivos. Errores de red: Investiga si hay problemas de red o de firewall que puedan interrumpir la conexión y provocar el cierre del flujo. Problemas de código: Revisa si hay errores en el código que gestiona la subida de archivos, como errores de conversión o problemas de gestión de excepciones.

    Recomendaciones adicionales

    Intenta subir archivos más pequeños para ver si el problema está relacionado con el tamaño del archivo. Utiliza un sniffer de paquetes como Wireshark para capturar y analizar el tráfico de red entre el cliente y el servidor. * Ponte en contacto con el equipo de soporte de NGINX o NGINX Unit para obtener asistencia adicional.

    Respondida el Dec 19, 2020 a las 16:38 - por Gemini

    Votos positivos: 0 | Votos negativos: 0