Pregunta

He estado escribiendo una pequeña aplicación que permitirá a las personas subir & amp; descargar archivos a mi He agregado un servicio web a esta aplicación para proporcionar la funcionalidad de carga / descarga de esa manera, pero no estoy muy seguro de qué tan bien mi implementación va a hacer frente a archivos grandes.

En este momento, las definiciones de la carga & amp; los métodos de descarga se ven así (escrito usando Apache CXF):

boolean uploadFile(@WebParam(name = "username") String username,
    @WebParam(name = "password") String password,
    @WebParam(name = "filename") String filename,
    @WebParam(name = "fileContents") byte[] fileContents)
    throws UploadException, LoginException;

byte[] downloadFile(@WebParam(name = "username") String username,
    @WebParam(name = "password") String password,
    @WebParam(name = "filename") String filename) throws DownloadException,
    LoginException;

Por lo tanto, el archivo se carga y descarga como una matriz de bytes. Pero si tengo un archivo de un tamaño estúpido (por ejemplo, 1 GB) seguramente esto intentará poner toda esa información en la memoria y bloqueará mi servicio.

Entonces, mi pregunta es: ¿es posible devolver algún tipo de flujo en su lugar? Me imagino que esto no va a ser terriblemente independiente del sistema operativo, sin embargo. Aunque conozco la teoría detrás de los servicios web, el aspecto práctico es algo sobre lo que todavía necesito recopilar un poco de información.

Saludos para cualquier entrada, Lee

¿Fue útil?

Solución

Stephen Denne tiene una implementación de Metro que satisface sus requisitos. Mi respuesta se proporciona a continuación después de una breve explicación de por qué ese es el caso.

La mayoría de las implementaciones de servicios web que se crean utilizando HTTP como protocolo de mensajes son compatibles con REST, ya que solo permiten patrones simples de envío-recepción y nada más. Esto mejora enormemente la interoperabilidad, ya que todas las distintas plataformas pueden comprender esta arquitectura simple (por ejemplo, un servicio web Java que habla con un servicio web .NET).

Si desea mantener esto, puede proporcionar fragmentación.

boolean uploadFile(String username, String password, String fileName, int currentChunk, int totalChunks, byte[] chunk);

Esto requeriría un poco de trabajo de pies en los casos en los que no obtengas los trozos en el orden correcto (o simplemente puedes pedir que los trozos vengan en el orden correcto), pero probablemente sería bastante fácil de implementar.

Otros consejos

Sí, es posible con Metro. Vea el ejemplo de Large Attachments , que parece que hace lo que usted quiere .

  

JAX-WS RI proporciona soporte para enviar y recibir archivos adjuntos de gran tamaño en forma de transmisión.

     
      
  • Use MTOM y DataHandler en el modelo de programación.
  •   
  • Convierta el DataHandler en StreamingDataHandler y use sus métodos.
  •   
  • Asegúrese de llamar a StreamingDataHandler.close () y también cierre la transmisión StreamingDataHandler.readOnce ().
  •   
  • Habilite la división de HTTP en el lado del cliente.
  •   

Cuando utiliza un servicio web estandarizado, el remitente y el receptor confían en la integridad de los datos XML enviados de uno a otro. Esto significa que una solicitud de servicio web y una respuesta solo están completas cuando se envió la última etiqueta. Teniendo esto en cuenta, un servicio web no se puede tratar como una transmisión.

Esto es lógico porque los servicios web estandarizados dependen del protocolo http. Ese es "sin estado", dirá que funciona como "conexión abierta ... enviar solicitud ... recibir datos ... cerrar solicitud". La conexión se cerrará al final, de todos modos. Entonces, algo como el streaming no está destinado a ser usado aquí. O puede colocar capas por encima de http (como servicios web).

Lo siento, pero por lo que puedo ver, no hay posibilidad de transmisión en servicios web. Lo que es peor, dependiendo de la implementación / configuración de un servicio web, el byte []: los datos pueden traducirse a Base64 y no a la etiqueta CDATA y la solicitud puede estar aún más hinchada.

P.S .: Sí, como escribieron otros, " chuinking " es posible. Pero esto no es una transmisión como tal ;-) - de todos modos, puede ayudarte.

Odio compartirlo con aquellos de ustedes que piensan que un servicio web de transmisión no es posible, pero en realidad, todas las solicitudes http se basan en la transmisión. Cada navegador que realiza un GET a un sitio web se basa en la transmisión. Cada llamada a un servicio web se basa en la transmisión. Si todo. No notamos esto en el nivel en el que estamos implementando servicios o páginas porque los niveles más bajos de la arquitectura se ocupan de esto por usted, pero se está haciendo.

¿Alguna vez has notado en un navegador que a veces puede llevar un tiempo recuperar una página? ¿El navegador sigue apareciendo mostrando el reloj de arena? Esto se debe a que el navegador está esperando en una secuencia.

Las secuencias son la razón por la que se deben enviar mime / tipos antes de los datos reales: todo es solo una secuencia de bytes en el navegador, no sería capaz de identificar una foto si no le dijeras lo que era primero. . También es la razón por la que tienes que pasar el tamaño de un binario antes de enviarlo: el navegador no podrá decir dónde se detiene la imagen y la página vuelve a aparecer.

Todo es solo un flujo de bytes al cliente. Si desea probar esto por sí mismo, simplemente retenga el flujo de salida en cualquier punto del procesamiento de una solicitud y ciérrelo (). Vas a explotar todo. El navegador dejará de mostrar inmediatamente el reloj de arena y mostrará un " no puede encontrar " o " restablecimiento de la conexión en el servidor " o algún otro mensaje similar.

Que mucha gente no sepa que todo esto se basa en la transmisión muestra cuánta información se ha colocado encima de ella. Algunos dirían demasiado, yo soy uno de ellos.

¡Buena suerte y feliz desarrollo! ¡Relaja esos hombros!

Para WCF, creo que es posible definir un miembro en un mensaje como transmisión y establecer el enlace de forma adecuada. He visto que esto funciona con wcf hablando con el servicio web de Java.

Debes configurar transferMode = " StreamedResponse " en la configuración de httpTransport y use mtomMessageEncoding (necesita usar una sección de enlace personalizada en la configuración).

Creo que una limitación es que solo puedes tener un solo miembro del cuerpo del mensaje si quieres transmitir (lo que tiene sentido).

Apache CXF admite el envío y la recepción de secuencias.

Una forma de hacerlo es agregar un método uploadFileChunk (byte [] chunkData, int size, int offset, int totalSize) (o algo así) que carga partes del archivo y la Los servidores lo escriben al disco.

Tenga en cuenta que una solicitud de servicio web básicamente se reduce a un único HTTP POST.

Si observa la salida de un archivo .ASMX en .NET, le muestra exactamente el aspecto de la solicitud y respuesta POST.

Chunking, como lo menciona @Guvante, va a ser lo más parecido a lo que quieres.

Supongo que podría implementar su propio código de cliente web para manejar TCP / IP y transmitir cosas a su aplicación, pero eso sería complejo por decir lo menos.

Creo que usar un servlet sencillo para esta tarea sería un enfoque mucho más fácil , o hay alguna razón por la que no puedes usar un servlet?

Por ejemplo, puede utilizar la Commons biblioteca de código abierto.

La biblioteca RMIIO para Java entrega un RemoteInputStream a través de RMI; solo necesitábamos RMI. aunque debería poder adaptar el código para trabajar sobre otros tipos de RMI. Esto puede ser de ayuda para usted, especialmente si puede tener una pequeña aplicación en el lado del usuario. La biblioteca se desarrolló con el propósito expreso de poder limitar el tamaño de los datos que se envían al servidor para evitar exactamente el tipo de situación que usted describe, efectivamente un ataque de DOS al rellenar un ram o un disco.

Con la biblioteca RMIIO, el lado del servidor decide la cantidad de datos que está dispuesta a extraer, donde con HTTP PUT y POST, el cliente toma la decisión, incluida la velocidad a la que empuja.

Sí, un servicio web puede hacer streaming. Creé un servicio web utilizando Apache Axis2 y MTOM para admitir la representación de documentos PDF desde XML. Dado que los archivos resultantes pueden ser bastante grandes, la transmisión fue importante porque no queríamos tenerlo todo en la memoria. Eche un vistazo a la documentación de Oracle en archivos adjuntos SOAP de streaming.

Alternativamente, puedes hacerlo tú mismo, y Tomcat creará los encabezados fragmentados. Este es un ejemplo de una función de controlador de resorte que se transmite.

 @RequestMapping(value = "/stream")
        public void hellostreamer(HttpServletRequest request, HttpServletResponse response) throws CopyStreamException, IOException  
{

            response.setContentType("text/xml");
            OutputStreamWriter writer = new OutputStreamWriter (response.getOutputStream());
            writer.write("this is streaming");
            writer.close();

    }

En realidad no es tan difícil " manejar TCP / IP y transmitir cosas a tu aplicación " ;. Prueba esto ...

class MyServlet extends HttpServlet
{
    public void doGet(HttpServletRequest request, HttpServletResponse response)
    {
        response.getOutputStream().println("Hello World!");
    }
}

Y eso es todo lo que hay que hacer. En el código anterior, respondió a una solicitud HTTP GET enviada desde un navegador y devolvió a ese navegador el texto " ¡Hola mundo! & Quot ;.

Ten en cuenta que " ¡Hola mundo! " no es un HTML válido, por lo que puede terminar con un error en el navegador, pero eso es todo lo que hay en él.

¡Buena suerte en tu desarrollo!

Rodney

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top