2008-09-25 28 views
28

He estado escribiendo una pequeña aplicación que permitirá a las personas cargar archivos de descarga de &. Agregué un servicio web a esta aplicación para proporcionar la funcionalidad de carga y descarga de esa manera, pero no estoy muy seguro de qué tan bien mi implementación va a hacer frente a archivos de gran tamaño.¿Puede un servicio web devolver una transmisión?

En el momento de las definiciones de los métodos de descarga de carga & 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; 

Así que el archivo se cargados y descargados como una matriz de bytes. Pero si tengo un archivo de algún tamaño estúpido (por ejemplo, 1GB), seguramente esto intentará poner toda esa información en la memoria y colgar mi servicio.

Así que mi pregunta es: ¿es posible devolver algún tipo de transmisión en su lugar? Sin embargo, me imagino que esto no va a ser terriblemente independiente del sistema operativo. Aunque conozco la teoría detrás de los servicios web, la parte práctica es algo de lo que todavía necesito obtener un poco de información.

Saludos para cualquier entrada, Lee

+0

alguna razón específica de por qué una cuestión de hace 5 años está activo de nuevo? ¿Respuestas desactualizadas? – Loko

Respuesta

6

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

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

Si desea mantener esto podría proporcionar fragmentación.

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

Esto requeriría una serie de paredes en los casos en que no consigue los trozos en el orden correcto (O simplemente puede requerir los trozos vienen en el orden correcto), pero probablemente sería bastante fácil de implementar .

+3

Conceptualmente, usted tiene razón, pero definitivamente hay maneras de evitar esta restricción (como se mencionó en @spdenne). Una buena solución sería usar MTOM. –

+0

Esto simplemente no es correcto. * Puedes * escribir un servicio web de transmisión. De hecho, HttpServletResponse tiene un método llamado getOutputStream(). – nont

+0

@nont: la mayoría de los servicios web están diseñados para ser compatibles con REST en la interfaz. Esto excluye operaciones interesantes como la transmisión, pero simplifica todas las operaciones para mejorar la interoperabilidad entre plataformas. Esto incluye la implementación básica de Java, que cierra la secuencia de salida antes de enviar un mensaje por lo que puedo decir de la API. – Guvante

0

Una forma de hacerlo es añadir un uploadFileChunk (byte [] chunkData, tamaño, int offset, int TotalSize) método (o algo así) que carga las partes del archivo y los servidores lo escribe el en el disco.

14

Sí, es posible con Metro. Consulte el ejemplo Large Attachments, que parece que hace lo que desea.

JAX-WS RI proporciona soporte para enviar y recibir archivos adjuntos de gran tamaño de forma continua.

  • Utilice MTOM y DataHandler en el modelo de programación.
  • Transfiere el DataHandler a StreamingDataHandler y utiliza sus métodos.
  • Asegúrese de llamar a StreamingDataHandler.close() y también cierre la secuencia de StreamingDataHandler.readOnce().
  • Habilita la fragmentación de HTTP en el lado del cliente.
3

Cuando se utiliza un servicio web estandarizado el emisor y el receptor no confían en la integridad de los datos XML enviar desde la una a la otra.Esto significa que la solicitud y la respuesta del servicio web solo se completan cuando se envió la última etiqueta. Teniendo esto en cuenta, un servicio web no puede tratarse como una transmisión.

Esto es lógico, ya que los servicios web estandarizados no se basan en el protocolo http. Que uno es "sin estado", dirá que funciona como "conexión abierta ... enviar solicitud ... ... recibir datos solicitud de cierre". La conexión se cerrará al final, de todos modos. Entonces, algo así como la transmisión no está destinado a ser utilizado aquí. O capas superiores a http (como servicios web).

Así que lo siento, pero por lo que puedo ver no hay posibilidad para la transmisión de servicios web. Lo que es peor: en función de la aplicación/configuración de un servicio web, byte [] - datos puede ser traducido a base 64 y no el CDATA-tag y la solicitud podría ser aún más hinchado.

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

0

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

Si nos fijamos en la salida de un archivo .asmx en .NET, le muestra exactamente lo que la solicitud y la respuesta posterior se verá así.

operaciones de fragmentación, como se ha mencionado por @Guvante, va a ser lo más parecido a lo que desea.

supongo que se podría implementar su propio código de cliente web para manejar el protocolo TCP/IP y cosas de flujo en su aplicación, pero que sería complejo para decir lo menos.

0

creo que el uso de un simple servlet para esta tarea sería un enfoque mucho más fácil, o hay alguna razón no se puede utilizar un servlet?

Por ejemplo, podría utilizar la biblioteca de código abierto Commons.

0

La biblioteca RMIIO para Java proporciona para entregar un RemoteInputStream través de RMI - sólo necesitamos RMI, aunque debe ser capaz de adaptar el código para trabajar sobre otros tipos de RMI. Esto puede ser útil para usted, especialmente si puede tener una pequeña aplicación en el lado del usuario. La biblioteca fue desarrollado con el propósito expreso de ser capaz de limitar el tamaño de los datos inserta en el servidor para evitar exactamente el tipo de situación que usted describe - con eficacia un ataque DoS llenando la memoria RAM o disco.

Con la biblioteca RMIIO, el lado del servidor puede decidir la cantidad de datos que desea extraer, donde con HTTP PUT y POST, el cliente toma esa decisión, incluida la velocidad a la que presiona.

1

Para WCF Creo que es posible definir un miembro de un mensaje en forma de corriente y establecer la unión apropiada - que he visto este trabajo con WCF hablar con el servicio web en Java.

Debe establecer transferMode = "StreamedResponse" en la configuración httpTransport y usar mtomMessageEncoding (necesita utilizar una sección de enlace personalizada en la configuración).

Creo que una limitación es que sólo puede tener un único miembro de cuerpo del mensaje si desea transmitir (que tipo de sentido).

+0

Ese es un estándar (por lo que no es solo .NET) y IIRC usan MTOM para esto. –

0

Sí, un servicio web puede hacer streaming. He creado un servicio web utilizando Apache Axis2 y masa máxima de despegue para apoyar la prestación de documentos PDF a partir de XML.Como los archivos resultantes podían ser bastante grandes, la transmisión era importante porque no queríamos mantener todo en la memoria. Eche un vistazo a la documentación de Oracle en streaming SOAP attachments.

O bien, puede hacerlo usted mismo, y tomcat creará los encabezados fragmentados. Este es un ejemplo de una función de controlador de primavera 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(); 

    } 
1

odio romperlo a aquellos de ustedes que piensan que un servicio de streaming web no es posible, pero en realidad, todas las peticiones HTTP son basados ​​corriente. Cada navegador que hace un GET a un sitio web se basa en la transmisión. Cada llamada a un servicio web se basa en secuencias. Si todo. No notamos esto en el nivel donde 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 ha notado en un navegador que a veces puede tomar un tiempo para obtener una página - el navegador sólo mantiene el arranque de distancia que muestra el reloj de arena? Eso es porque el navegador está esperando en una transmisión.

Las transmisiones son la razón por la que se deben enviar mime/types antes de los datos reales; todo es solo un flujo de bytes para el navegador, no podría identificar una foto si no se le dice qué era primero. También es el motivo por el que debe pasar el tamaño de un archivo binario antes de enviarlo; el navegador no podrá decir dónde se detiene la imagen y la página vuelve a aparecer.

Todo esto es sólo un flujo de bytes para el cliente. Si quiere probarlo por sí mismo, simplemente agárrese del flujo de salida en cualquier punto del procesamiento de una solicitud y ciérrela(). Explosionarás todo. El navegador dejará de mostrar el reloj de arena de inmediato y mostrará un mensaje de "No se puede encontrar" o "Restablecer conexión en el servidor" o algún otro mensaje similar.

que mucha gente no sabe que todas estas cosas es simplemente espectáculos basados ​​corriente la cantidad de cosas ha sido capas en la parte superior de la misma. Algunos dirían muchas cosas, yo soy uno de esos.

Buena suerte y feliz desarrollo - relajar los hombros!

0

En realidad no es tan difícil de "manejar el protocolo TCP/IP y cosas de flujo en su aplicación". Pruebe esto ...

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

Y eso es todo. En el código anterior, respondió a una solicitud HTTP GET enviada desde un navegador y le devolvió el texto "¡Hola, mundo!".

Ten en cuenta que "Hello World!" no es HTML válido, por lo que puede terminar con un error en el navegador, pero eso es todo lo que hay que hacer.

buena suerte en su desarrollo!

Rodney

Cuestiones relacionadas