Domanda

Ho scritto una piccola applicazione che permetterà alle persone di caricare & amp; scarica i file per me. Ho aggiunto un servizio Web a questa applciation per fornire la funzionalità di upload / download in questo modo, ma non sono troppo sicuro di come la mia implementazione riuscirà a gestire file di grandi dimensioni.

Al momento le definizioni di upload & amp; i metodi di download sono simili al seguente (scritti 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;

Quindi il file viene caricato e scaricato come array di byte. Ma se avrò un file di dimensioni stupide (ad es. 1 GB) sicuramente questo proverà a mettere tutte queste informazioni in memoria e manderà in crash il mio servizio.

Quindi la mia domanda è: è possibile invece restituire un qualche tipo di stream? Immagino che questo non sarà terribilmente indipendente dal SO. Sebbene conosca la teoria alla base dei servizi Web, il lato pratico è qualcosa su cui devo ancora raccogliere un po 'di informazioni.

Saluti per qualsiasi input, Lee

È stato utile?

Soluzione

Stephen Denne ha un'implementazione Metro che soddisfa le tue esigenze. La mia risposta viene fornita di seguito dopo una breve spiegazione sul perché sia ??così.

La maggior parte delle implementazioni di servizi Web create utilizzando HTTP come protocollo di messaggio sono conformi a REST, in quanto consentono solo semplici schemi di invio e ricezione e nient'altro. Ciò migliora notevolmente l'interoperabilità, poiché tutte le varie piattaforme sono in grado di comprendere questa semplice architettura (ad esempio un servizio Web Java che parla con un servizio Web .NET).

Se si desidera mantenerlo, è possibile fornire blocchi.

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

Ciò richiederebbe un po 'di gioco di gambe nei casi in cui non si ottengono i pezzi nell'ordine giusto (o si può semplicemente richiedere che i pezzi vengano nell'ordine giusto), ma probabilmente sarebbe abbastanza facile da implementare.

Altri suggerimenti

Sì, è possibile con Metro. Guarda l'esempio Large Attachments , che sembra fare quello che vuoi .

  

Il RI JAX-WS fornisce supporto per l'invio e la ricezione di allegati di grandi dimensioni in modo streaming.

     
      
  • Utilizzare MTOM e DataHandler nel modello di programmazione.
  •   
  • Trasmetti DataHandler a StreamingDataHandler e usa i suoi metodi.
  •   
  • Assicurati di chiamare StreamingDataHandler.close () e di chiudere anche il flusso StreamingDataHandler.readOnce ().
  •   
  • Abilita il blocco HTTP sul lato client.
  •   

Quando si utilizza un servizio Web standardizzato, il mittente e il destinatario si basano sull'integrità dei dati XML inviati dall'uno all'altro. Ciò significa che una richiesta e una risposta del servizio Web sono complete solo quando è stato inviato l'ultimo tag. Tenendo presente questo, un servizio web non può essere trattato come un flusso.

Questo è logico perché i servizi web standardizzati si basano sul protocollo http. Quello è "apolide", dirà che funziona come "apri connessione ... invia richiesta ... ricevi dati ... chiudi richiesta". La connessione verrà comunque chiusa alla fine. Quindi qualcosa come lo streaming non è destinato a essere utilizzato qui. Oppure passa sopra http (come i servizi Web).

Mi dispiace, ma per quanto posso vedere non c'è possibilità di streaming nei servizi web. Ancora peggio: a seconda dell'implementazione / configurazione di un servizio web, byte [] - i dati potrebbero essere tradotti in Base64 e non nel tag CDATA e la richiesta potrebbe diventare ancora più gonfia.

P.S .: Sì, come altri hanno scritto, "chuinking" è possibile. Ma questo non è uno streaming in quanto tale ;-) - comunque, può aiutarti.

Odio spezzarlo per quelli di voi che pensano che un servizio web in streaming non sia possibile, ma in realtà tutte le richieste http sono basate sul flusso. Ogni browser che esegue un GET su un sito Web è basato su stream. Ogni chiamata a un servizio Web è basata sullo streaming. Si a tutti. Non lo notiamo al livello in cui stiamo implementando servizi o pagine perché livelli più bassi dell'architettura si occupano di questo per te - ma è stato fatto.

Hai mai notato in un browser che a volte può essere necessario un po 'di tempo per recuperare una pagina: il browser continua a spegnersi mostrando la clessidra? Questo perché il browser è in attesa su uno stream.

I flussi sono il motivo per cui mime / tipi devono essere inviati prima dei dati effettivi: è tutto solo un flusso di byte per il browser, non sarebbe in grado di identificare una foto se non le dicessi di cosa si trattava prima . È anche il motivo per cui devi superare le dimensioni di un file binario prima di inviarlo: il browser non sarà in grado di dire dove si ferma l'immagine e la pagina riprende di nuovo.

È tutto solo un flusso di byte per il client. Se vuoi dimostrarlo tu stesso, procurati semplicemente il flusso di output in qualsiasi momento dell'elaborazione di una richiesta e chiudilo (). Farai saltare tutto. Il browser smetterà immediatamente di mostrare la clessidra e visualizzerà un messaggio "impossibile trovare" o "reset connessione al server" o qualche altro messaggio simile.

Il fatto che molte persone non sappiano che tutta questa roba è basata sul flusso mostra quanto roba è stata sovrapposta. Alcuni direbbero troppe cose - io sono uno di quelli.

Buona fortuna e buon sviluppo - rilassa quelle spalle!

Per WCF penso che sia possibile definire un membro di un messaggio come stream e impostare l'associazione in modo appropriato - Ho visto questo lavoro con WCF parlare al servizio web Java.

Devi impostare transferMode = " StreamedResponse " nella configurazione di httpTransport e utilizzare mtomMessageEncoding (è necessario utilizzare una sezione di associazione personalizzata nella configurazione).

Penso che una limitazione sia che puoi avere un solo membro del corpo del messaggio se vuoi lo streaming (che tipo di senso ha senso).

Apache CXF supporta l'invio e la ricezione di flussi.

Un modo per farlo è aggiungere un metodo uploadFileChunk (byte [] chunkData, int size, int offset, int totalSize) (o qualcosa del genere) che carica parti del file e il server lo scrive sul disco.

Tieni presente che una richiesta di servizio Web si riduce sostanzialmente a un singolo POST HTTP.

Se guardi l'output di un file .ASMX in .NET, mostra esattamente come appariranno la richiesta e la risposta POST.

Chunking, come menzionato da @Guvante, sarà la cosa più vicina a ciò che vuoi.

Suppongo che potresti implementare il tuo codice client Web per gestire il TCP / IP e trasmettere le cose nella tua applicazione, ma sarebbe a dir poco complesso.

Penso che usare un semplice servlet per questo compito sarebbe un approccio molto più semplice o c'è qualche motivo per cui non puoi usare un servlet?

Ad esempio, è possibile utilizzare la Commons libreria open source.

La libreria RMIIO per Java prevede la gestione di RemoteInputStream su RMI: avevamo solo bisogno di RMI, anche se dovresti essere in grado di adattare il codice per lavorare su altri tipi di RMI. Questo può esserti di aiuto, specialmente se puoi avere una piccola applicazione sul lato utente. La libreria è stata sviluppata con lo scopo esplicito di essere in grado di limitare la dimensione dei dati inviati al server per evitare esattamente il tipo di situazione che descrivi - efficacemente un attacco DOS riempiendo ram o disco.

Con la libreria RMIIO, il lato server può decidere quanti dati è disposto a estrarre, dove con HTTP PUT e POST il cliente prende questa decisione, inclusa la velocità con cui spinge.

Sì, un servizio web può eseguire lo streaming. Ho creato un servizio web usando Apache Axis2 e MTOM per supportare il rendering di documenti PDF da XML. Poiché i file risultanti potrebbero essere piuttosto grandi, lo streaming era importante perché non volevamo tenere tutto in memoria. Dai un'occhiata alla documentazione di Oracle su streaming SOAP allegati.

In alternativa, puoi farlo da solo e tomcat creerà le intestazioni Chunked. Questo è un esempio di una funzione di controller a molla che viene riprodotta in streaming.

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

    }

In realtà non è così difficile " gestire il TCP / IP e trasmettere cose nella tua applicazione " ;. Prova questo ...

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

E questo è tutto. Nel codice sopra, hai risposto a una richiesta GET HTTP inviata da un browser e hai restituito a quel browser il testo " Hello World! & Quot ;.

Tieni presente che " Hello World! " non è un codice HTML valido, quindi potresti ritrovarti con un errore nel browser, ma questo è davvero tutto ciò che c'è da fare.

Buona fortuna nel tuo sviluppo!

Rodney

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top