Pergunta

Eu tenho escrito um pequeno aplicativo que permitirá que as pessoas de upload e download de arquivos para mim. Eu adicionei um serviço web para este applciation para fornecer a funcionalidade de upload / download dessa forma, mas eu não estou muito certo sobre o quão bem minha implementação vai lidar com arquivos grandes.

No momento as definições do upload e download de métodos olhar como este (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;

Assim, o arquivo é carregado e descarregado como um array de bytes. Mas se eu tiver um arquivo de algum tamanho estúpido (por exemplo, 1GB) certamente isso vai tentar colocar toda essa informação na memória e bater o meu serviço.

Assim, a minha pergunta é - é possível retornar algum tipo de fluxo em vez disso? Eu imagino que isso não vai ser terrivelmente OS embora independente. Embora eu saiba que a teoria por trás de serviços web, o lado prático é algo que eu ainda preciso pegar um pouco de informação sobre.

Felicidades para qualquer entrada, Lee

Foi útil?

Solução

Stephen Denne tem uma implementação Metro que satisfaz sua exigência. Minha resposta é fornecida abaixo após um curto explination a respeito de porque este é o caso.

A maioria implementações de serviços da Web que são construídos utilizando HTTP como o protocolo de mensagem são compatíveis REST, na medida em que só permitem enviar-recebem padrões simples e nada mais. Isto melhora a interoperabilidade, tal como todas as várias plataformas pode entender essa arquitetura simples (por exemplo, um serviço web Java conversando com um serviço .NET web).

Se você quiser manter esse você poderia fornecer chunking.

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

Isso exigiria algum footwork nos casos em que você não obter os pedaços na ordem certa (Ou você pode apenas exigir que os pedaços vêm na ordem certa), mas provavelmente seria muito fácil de implementar.

Outras dicas

Sim, é possível com a Metro. Veja os anexos grandes exemplo, que parece que faz o que quiser .

JAX-WS RI fornece suporte para enviar e receber anexos grandes de uma forma de streaming.

  • Use MTOM e DataHandler no modelo de programação.
  • Lançai a DataHandler para StreamingDataHandler e usar seus métodos.
  • Certifique-se de chamar StreamingDataHandler.close () e também perto do córrego StreamingDataHandler.readOnce ().
  • Ative HTTP chunking no lado do cliente.

Quando você usa um serviço de web padronizado o emissor eo receptor faz confiar na integridade do XML de envio dos dados de um para o outro. Isto significa que uma solicitação de serviço web e resposta só é completa quando a última tag foi enviado. Tendo isso em mente, um serviço web não podem ser tratadas como um fluxo.

Esta é lógico, porque os serviços web padronizados não contar com o http-protocolo. Que um é "apátrida", dirá ele funciona como "solicitação de conexão ... send aberto ... receber dados ... Fechar pedido". A ligação será fechado na extremidade, de qualquer maneira. Então, algo como streaming não se destina a ser utilizado aqui. Ou camadas acima http (como serviços web).

Então, desculpe, mas tanto quanto eu posso ver, não há possibilidade para streaming na web services. Pior ainda:. Dependendo da implementação / configuração de um serviço web, byte [] - os dados podem ser traduzidos para Base64 e não o CDATA-tag ea solicitação pode ficar ainda mais inchado

P.S .: Sim, como outros escreveu, "chuinking" é possível. Mas isso não está fluindo como tal ;-) -. De qualquer forma, ele pode ajudá-lo

Eu odeio a quebrá-lo para aqueles de vocês que acho que um serviço web ao vivo não é possível, mas, na realidade, todas as solicitações HTTP são fluxo de base. Cada navegador fazendo um GET para um web site é baseado fluxo. Cada chamada para um serviço web é baseada fluxo. Sim, todos. Nós não percebe isso no nível em que estamos implementando serviços ou páginas porque os níveis inferiores da arquitetura estão lidando com isso por você -. Mas está sendo feito

Você já reparou em um navegador que às vezes pode demorar um pouco para buscar uma página - o navegador só continua acionando afastado mostrando a ampulheta? Isso é porque o browser está esperando em um córrego.

Streams são a razão mime / tipos têm de ser enviados antes dos dados reais - tudo é apenas um fluxo de bytes para o navegador, que não seria capaz de identificar uma foto se você não disse a ele o que era primeiro . É também por isso que você tem que passar o tamanho de um binário antes de enviar -. O navegador não será capaz de dizer onde a imagem pára ea página pega novamente

É tudo apenas um fluxo de bytes para o cliente. Se você quer provar isso por si mesmo, é só pegar um porão do fluxo de saída em qualquer ponto no processamento de um pedido e close ()-lo. Você vai explodir tudo. O navegador irá parar imediatamente mostrando a ampulheta, e irá mostrar uma "redefinição de conexão no servidor" "não é possível encontrar" ou ou algum outro tal mensagem.

que muitas pessoas não sabem que todo este material está Stream mostra apenas quanto material foi camadas em cima dele com base. Alguns diriam muita coisa -. Eu sou um daqueles

Boa sorte e desenvolvimento feliz - relaxar os ombros

Para WCF Eu acho que é possível definir um membro em uma mensagem como fluxo e definir a ligação de forma adequada -. Eu vi esse trabalho com o WCF conversando com serviço de web Java

Você precisa definir o transferMode = "StreamedResponse" no HttpTransport configuração e uso mtomMessageEncoding (necessidade de usar uma seção de ligação personalizada no config).

Eu acho que uma limitação é que você só pode ter um único membro do corpo da mensagem se você deseja transmitir (que tipo de faz sentido).

Apache CXF suporta o envio e recebimento de fluxos.

Uma maneira de fazer isso é adicionar um uploadFileChunk (byte [] chunkData, tamanho int, offset int, totalSize int) método (ou algo parecido) que envia partes do arquivo eo servidores escreve-o para o disco.

Tenha em mente que uma solicitação de serviço web basicamente se resume a um único HTTP POST.

Se você olhar para a saída de um arquivo .asmx em .NET, que mostra exatamente o que a solicitação POST ea resposta será semelhante.

Chunking, como mencionado por @Guvante, vai ser a coisa mais próxima que você quer.

Eu suponho que você poderia implementar seu próprio código de cliente web para lidar com o TCP / IP e as coisas fluxo em sua aplicação, mas que seria complexo para dizer o mínimo.

Eu acho que usando um simples servlet para esta tarefa seria uma abordagem muito mais fácil ou há alguma razão você não pode usar um servlet?

Por exemplo, você poderia usar o Commons biblioteca de código aberto.

O RMIIO biblioteca para Java prevê entregar um RemoteInputStream através RMI - nós só precisava de RMI, mas você deve ser capaz de adaptar o código para o trabalho sobre outros tipos de RMI. Isto pode ser de ajuda para você - especialmente se você pode ter uma pequena aplicação no lado do usuário. A biblioteca foi desenvolvida com a finalidade expressa de ser capaz de limitar o tamanho dos dados empurrados para o servidor para evitar exatamente o tipo de situação que você descreve -. Efetivamente um ataque DOS através do preenchimento de RAM ou disco

Com a biblioteca RMIIO, o lado do servidor começa a decidir a quantidade de dados que está disposta a puxar, onde com HTTP PUT e postos, o cliente começa a tomar essa decisão, incluindo a taxa em que ele empurra.

Sim, um webservice pode fazer streaming de. Eu criei um webservice usando Apache Axis2 e MTOM para suportar renderização documentos PDF a partir de XML. Uma vez que os arquivos resultantes podem ser muito grandes, streaming foi importante porque nós não queremos manter tudo na memória. Dê uma olhada na documentação do Oracle no streaming de anexos SOAP.

Como alternativa, você pode fazê-lo sozinho, e tomcat irá criar os cabeçalhos em partes. Este é um exemplo de uma função de controlador de mola que fluxos.

 @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();

    }

Na verdade não é tão difícil de "lidar com o TCP / IP e as coisas fluxo em sua aplicação". Tente isto ...

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

E isso é tudo que existe para ela. Você, no código acima, respondeu a uma solicitação HTTP GET enviado a partir de um navegador, e voltou para que o navegador do texto "Olá mundo!".

Tenha em mente que "Olá mundo!" não é HTML válido, então você pode acabar com um erro no navegador, mas que realmente é tudo que existe para ela.

Boa sorte no seu desenvolvimento!

Rodney

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top