簡體   English   中英

使用播放框架和第三方API流式傳輸大型文件

[英]Streaming large files with play framework and third party API

我正在寫一個播放2應用程序,我正在努力解決文件流問題。 我使用第三方API檢索我的文件,其方法具有以下簽名:

FileMetadata getFile(OutputStream destination, String fileId)

在傳統的Servlet應用程序中,如果我想將內容發送到我的客戶端,我會做類似的事情:

HttpServletResponse resp;
myService.getFile(resp.getOutpuStream, fileId);

我的問題是,在我的Play 2 Controller類中,我無法訪問底層的OuputStream,因此我的控制器方法的最簡單實現是:

public static downloadFile(String id) {
    ByteArrayOutputStream baos = new BAOS(...);
    myApi.getFile(baos,id); //Load inside temp Array      
    ByteArrayInputStream bais = new BAIS(baos.toByteArray())
    return Ok(bais);
 }

它可以工作,但它需要在服務之前將整個內容加載到內存中,因此它不是一個選項(文件可能很大)。

我在考慮一個解決方案,包括:

  • 在我的控制器中定義ByteArrayOutputStream(baos)
  • 使用此參數中的baos調用第三方API
  • 一旦第三方API寫入內容,就使用play框架的塊返回來發送baos的內容

問題是我不知道是否可能(調用getFile是阻塞所以它需要多個線程與共享OutputStream),也不是它有點過分。

有人遇到過這種問題並找到了解決方案嗎? 我提議的解決方案能解決我的問題嗎

任何見解將不勝感激。

謝謝

編輯1基於kheraud建議我已經設法有一個工作但仍然不完美的解決方案(下面的代碼)。

不幸的是,如果在調用getFile方法期間出現問題,則不會將錯誤發送回客戶端(因為我返回了Ok)並且瀏覽器無限期地等待一個永遠不會出現的文件。

有辦法處理這種情況嗎?

public static Result downloadFile(String fileId {    
      Thread readerThread = null;
      try {
          PipedOutputStream pos = new PipedOutputStream();
          PipedInputStream pis = new PipedInputStream(pos); 
          //Reading must be done in another thread
          readerThread = new DownloadFileWorker(fileId,pos);
          readerThread.start();

          return ok(pis);
      } catch (Exception ex) {
          ex.printStackTrace();
          return internalServerError(ex.toString());

      }
  }

static class DownloadFileWorker extends Thread{
      String fileId;  
      PipedOutputStream pos;

      public DownloadFileWorker(String fileId, PipedOutputStream pos) {
        super();
        this.fileId = fileId
        this.pos = pos;
    }

    public void run(){
          try {
              myApi.getFile(pos,fileId);
              pos.close();
          } catch (Exception ex) {
              ex.printStackTrace();
          }
      }
}

編輯2

我找到了一種避免無限加載頁面的方法,只需在工作線程的catch()部分添加一個pos.close即可。 客戶端最終得到一個零KB文件,但我想這比無限等待更好。

Play2 Scala框架中有一些內容: Enumerators 這與您的想法非常接近。

您應該查看此文檔頁面以獲取詳細信息

我沒有在Play2 Java API中找到類似的東西,但是查看fw代碼源,你有一個:

public static Results.Status ok(java.io.InputStream content, int chunkSize)

接縫是你正在尋找的方法。 可以在play.mvc.Resultsplay.core.j.JavaResults類中找到該實現。

在游戲中! 郵件列表,最近有一個關於同一主題的討論:

https://groups.google.com/forum/#!topic/play-framework/YunJzgxPKsU/discussion

它包含一個小片段,允許非scala-literates(像我一樣)使用Play!的scala流媒體界面。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM