java - tool - servicios web apache cxf
¿Puede un servicio web devolver una transmisión? (12)
Creo que usar un servlet simple 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, podría usar la biblioteca de código abierto de Commons .
He estado escribiendo una pequeña aplicación que permitirá a las personas cargar y descargar archivos para mí. 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.
Por el momento, las definiciones de los métodos de carga y descarga se ven así (escritas con 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;
Entonces, el archivo se carga y descarga 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.
Entonces 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 por cualquier entrada, Lee
Cuando utiliza un servicio web estandarizado, el remitente y el receptor dependen de la integridad del envío de datos XML del uno al otro. 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 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 así como la transmisión no está destinado a ser utilizado aquí. O capas superiores a http (como servicios web).
Lo siento, pero por lo que puedo ver, no hay posibilidad de transmisión en servicios web. Peor aún: dependiendo de la implementación / configuración de un servicio web, byte [] - los datos pueden traducirse a Base64 y no a la etiqueta CDATA y la solicitud puede ser aún más inflada.
PD: Sí, como otros escribieron, "chucking" es posible. Pero esto no es transmisión como tal ;-) - de todos modos, puede ser útil.
En realidad, no es tan difícil "manejar el TCP / IP y transmitir cosas a su 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 le devolvió el texto "¡Hola, mundo!".
Tenga 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 tu desarrollo!
Rodney
La biblioteca RMIIO para Java proporciona la transferencia de 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 útil para usted, especialmente si puede tener una pequeña aplicación en el lado del usuario. La biblioteca fue desarrollada con el propósito expreso de poder limitar el tamaño de los datos enviados al servidor para evitar exactamente el tipo de situación que usted describe; de hecho, es un ataque de DOS llenando RAM o disco.
Con la biblioteca RMIIO, el lado del servidor puede decidir la cantidad de datos que está dispuesto a extraer, donde con HTTP PUT y POST, el cliente toma esa decisión, incluida la velocidad a la que presiona.
Odio tener que decírselo a 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 secuencias. 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 has notado en un navegador que a veces puede tomar un tiempo buscar una página, el navegador simplemente 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 le dijiste 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 es solo una secuencia 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 sepa que todo esto está basado en stream muestra cuánto material se ha superpuesto encima. Algunos dirían muchas cosas, yo soy uno de esos.
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 la vinculación de manera apropiada: he visto que esto funciona con wcf hablando con el servicio web de Java.
Debe configurar transferMode = "StreamedResponse" en la configuración httpTransport y usar mtomMessageEncoding (necesita usar una sección de enlace personalizada en la configuración).
Creo que una limitación es que solo puedes tener un único miembro del cuerpo del mensaje si quieres transmitir (lo cual tiene sentido).
Sí, es posible con Metro. Vea el ejemplo de Grandes Anexos , que parece que hace lo que quiere.
JAX-WS RI proporciona soporte para enviar y recibir archivos adjuntos de gran tamaño de forma continua.
- Use MTOM y DataHandler en el modelo de programación.
- Eche el DataHandler a StreamingDataHandler y use sus métodos.
- Asegúrese de llamar a StreamingDataHandler.close () y también cierre la transmisión StreamingDataHandler.readOnce ().
- Habilite la fragmentación de HTTP en el lado del cliente.
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. 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 sobre la transmisión de archivos adjuntos SOAP.
Alternativamente, puede hacerlo usted mismo, y Tomcat creará los encabezados Chunked. 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();
}
Tenga en cuenta que una solicitud de servicio web básicamente se reduce a un único HTTP POST.
Si observa el resultado de un archivo .ASMX en .NET, le muestra exactamente cómo se verá la solicitud y la respuesta POST.
Chunking, como lo menciona @Guvante, va a ser lo más cercano a lo que quieres.
Supongo que podría implementar su propio código de cliente web para manejar el TCP / IP y transmitir cosas a su aplicación, pero eso sería complejo por decir lo menos.
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 los servidores lo escriben en el disco.
Apache CXF admite el envío y la recepción de transmisiones.
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 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 algo de trabajo de pies en los casos en que no consigas los trozos en el orden correcto (o puedes simplemente exigir que los trozos entren en el orden correcto), pero probablemente sería bastante fácil de implementar.