web-dev-qa-db-ja.com

Webサービスはストリームを返すことができますか?

私は、人々が私にファイルをアップロードおよびダウンロードできるようにする小さなアプリケーションを書いてきました。このアプリケーションにWebサービスを追加して、アップロード/ダウンロード機能をそのように提供しましたが、実装が大きなファイルをどれだけうまく処理できるかについてはよくわかりません。

現時点では、アップロードとダウンロードのメソッドの定義は次のようになっています(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;

したがって、ファイルはバイト配列としてアップロードおよびダウンロードされます。しかし、私がいくつかの愚かなサイズ(たとえば1GB)のファイルを持っている場合、これは確かにそのすべての情報をメモリに入れようとし、私のサービスをクラッシュさせます。

だから私の質問は-代わりにある種のストリームを返すことは可能ですか?ただし、これがOSに大きく依存することはないと思います。私はWebサービスの背後にある理論を知っていますが、実用的な側面については、まだ少し情報を得る必要があります。

どんな入力にも乾杯、リー

28
Lee Theobald

Stephen Denne 要件を満たすMetro実装があります。なぜそうなるのかについて簡単に説明した後、私の答えを以下に示します。

メッセージプロトコルとしてHTTPを使用して構築されたほとんどのWebサービス実装は、単純な送受信パターンのみを許可するという点でREST準拠)です。これにより、さまざまなプラットフォームすべてと同様に、相互運用性が大幅に向上します。この単純なアーキテクチャを理解できます(たとえば、.NET Webサービスと通信するJava Webサービス))。

これを維持したい場合は、チャンクを提供できます。

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

チャンクを正しい順序で取得できない場合(またはチャンクを正しい順序で取得するように要求することもできます)、これにはいくつかのフットワークが必要になりますが、実装はおそらくかなり簡単です。

6
Guvante

はい、Metroで可能です。 Large Attachments の例を参照してください。これは、必要なことを実行しているように見えます。

JAX-WS RIは、ストリーミング方式で大きな添付ファイルを送受信するためのサポートを提供します。

  • プログラミングモデルでMTOMとDataHandlerを使用します。
  • DataHandlerをStreamingDataHandlerにキャストし、そのメソッドを使用します。
  • StreamingDataHandler.close()を呼び出し、StreamingDataHandler.readOnce()ストリームも閉じるようにしてください。
  • クライアント側でHTTPチャンクを有効にします。
14
Stephen Denne

標準化されたWebサービスを使用する場合、送信者と受信者は、一方から他方に送信されるXMLデータの整合性に依存します。これは、最後のタグが送信されたときにのみWebサービスの要求と応答が完了することを意味します。これを念頭に置いて、Webサービスをストリームとして扱うことはできません。

標準化されたWebサービスはhttpプロトコルに依存しているため、これは論理的です。これは「ステートレス」であり、「接続を開く...リクエストを送信する...データを受信する...リクエストを閉じる」のように機能します。とにかく、接続は最後に閉じられます。したがって、ストリーミングのようなものはここで使用することを意図していません。または、httpの上に重ねます(Webサービスのように)。

申し訳ありませんが、私が見る限り、Webサービスでストリーミングする可能性はありません。さらに悪いことに、Webサービスの実装/構成によっては、byte []-データがCDATAタグではなくBase64に変換され、リクエストがさらに肥大化する可能性があります。

追伸:うん、他の人が書いたように、「チュインキング」は可能です。しかし、これはストリーミングそのものではありません;-)-とにかく、それはあなたを助けるかもしれません。

3
Georgi

Apache CXF ストリームの送受信をサポートします。

1
novice

ストリーミングWebサービスが不可能だと思っている人には、それを壊したくありませんが、実際には、すべてのhttpリクエストはストリームベースです。 WebサイトへのGETを実行するすべてのブラウザはストリームベースです。 Webサービスへのすべての呼び出しは、ストリームベースです。はい、すべてです。アーキテクチャの下位レベルがこれを処理しているため、サービスまたはページを実装しているレベルではこれに気づきませんが、実行されています。

ブラウザでページを取得するのに時間がかかることがあることに気付いたことがありますか?ブラウザは砂時計を表示し続けますか?これは、ブラウザがストリームを待機しているためです。

ストリームは、mime/typesを実際のデータの前に送信する必要がある理由です-それはすべてブラウザへの単なるバイトストリームであり、最初に何であるかを伝えないと写真を識別できません。また、送信する前にバイナリのサイズを渡す必要があるのもそのためです。ブラウザは画像が停止した場所を認識できず、ページが再び表示されます。

それはすべて、クライアントへの単なるバイトのストリームです。これを自分で証明したい場合は、リクエストの処理の任意の時点で出力ストリームを取得し、それをclose()します。あなたはすべてを爆破します。ブラウザはすぐに砂時計の表示を停止し、「見つかりません」または「サーバーで接続がリセットされました」などのメッセージを表示します。

多くの人がこれらすべてがストリームベースであることを知らないということは、その上にどれだけのものが重ねられているかを示しています。あまりにも多くのことを言う人もいます-私はその一人です。

幸運と幸せな開発-それらの肩をリラックスさせてください!

1
Rodney Barbati

WCFの場合、メッセージのメンバーをストリームとして定義し、バインディングを適切に設定することは可能だと思います。wcfがJava Webサービスと通信することでこの作業を確認しました。

HttpTransport構成でtransferMode = "StreamedResponse"を設定し、mtomMessageEncodingを使用する必要があります(構成でカスタムバインディングセクションを使用する必要があります)。

1つの制限は、ストリーミングする場合は1つのメッセージ本文メンバーしか持てないことだと思います(これは理にかなっています)。

1
Richard

これを行う1つの方法は、ファイルの一部をアップロードしてサーバーが書き込むploadFileChunk(byte [] chunkData、int size、int offset、int totalSize)メソッド(またはそのようなもの)を追加することです。ディスクへ。

0
Pop Catalin

Webサービスリクエストは基本的に単一のHTTPPOSTに要約されることに注意してください。

.NETで.ASMXファイルの出力を見ると、POSTリクエストとレスポンスがどのようになるかが正確にわかります。

@Guvanteが述べたように、チャンキングはあなたが望むものに最も近いものになるでしょう。

TCP/IPを処理し、アプリケーションにストリーミングする独自のWebクライアントコードを実装できると思いますが、控えめに言ってもそれは複雑です。

0
Eric Z Beard

実際、「TCP/IPを処理して、アプリケーションにストリーミングする」ことはそれほど難しくありません。これを試して...

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

そして、それがすべてです。上記のコードで、ブラウザから送信されたHTTP GETリクエストに応答し、そのブラウザに「HelloWorld!」というテキストを返しました。

「HelloWorld!」ということを忘れないでください。は有効なHTMLではないため、ブラウザでエラーが発生する可能性がありますが、実際にはそれだけです。

あなたの開発に幸運を!

ロドニー

0
Rodney Barbati

このタスクに単純な servlet を使用する方がはるかに簡単なアプローチだと思いますか、それともサーブレットを使用できない理由はありますか?

たとえば、 Commons オープンソースライブラリを使用できます。

0
Drejc

はい、Webサービスはストリーミングを実行できます。 ApacheAxis2とMTOMを使用してXMLからのドキュメントのレンダリングをサポートするWebサービスを作成しましたPDF XMLからのドキュメント。結果のファイルは非常に大きくなる可能性があるため、すべてをメモリに保持したくないため、ストリーミングが重要でした。 ストリーミングSOAP添付ファイル。 )に関するOracleのドキュメントをご覧ください。

または、自分で行うこともできます。Tomcatがチャンクヘッダーを作成します。これは、ストリーミングするスプリングコントローラー関数の例です。

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

    }
0
nont

[〜#〜] rmiio [〜#〜] ライブラリfor Javaは、RMIを介してRemoteInputStreamを処理するために提供されます-必要なのはRMIだけですが、コードを他のタイプのRMIで機能するように適合させます。これは、特にユーザー側に小さなアプリケーションを使用できる場合に役立つ可能性があります。ライブラリは、データのサイズを制限できるという明確な目的で開発されました。あなたが説明する状況のタイプを正確に回避するためにサーバーにプッシュされます-事実上、RAMまたはディスクをいっぱいにすることによるDOS攻撃。

RMIIOライブラリを使用すると、サーバー側はプルするデータの量を決定できます。HTTPPUTおよびPOSTを使用すると、クライアントはプッシュ速度を含めてその決定を行うことができます。

0
Kyle Burton