2011-08-26 95 views
1

我正在嘗試編寫基於java-servlet的小型webproxy。該代理具有 只有一個任務:Java-Servlet:對Quicktime視頻進行流式處理會導致ClientAbortException

  1. HTML應傳遞給發送請求的客戶端(GET與目的端口80的請求通過防火牆規則被重新路由到代理)。
  2. 嵌入式QuickTime視頻應該被另一個QuickTime視頻替換,並且應該傳遞給客戶端而不是最初請求的(這裏也是,客戶端的最初發送的GET請求首先被重新路由到代理,代理檢測到請求的內容類型不是HTML,並從這個問題得出結論:在這種特殊情況下內容必須是快速時間視頻(見下面的HTML))。因此,代理應將特定視頻發送/流式傳輸給客戶端。

這應該發生的是要由客戶端請求以下HTML文件:

<html> 
<head> 

<h1> Heading!</h1> 
</head> 
<body> 

<h1>My First Heading</h1> 

<object width="160" height="144" 
classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" 
codebase="http://www.apple.com/qtactivex/qtplugin.cab"> 
<param name="src" value="final_lion.mov"> 
<param name="autoplay" value="true"> 
<param name="controller" value="false"> 

<embed src="final_lion.mov" width="480" height="432" 
autoplay="true" controller="false" 
pluginspage="http://www.apple.com/quicktime/download/"> 
</embed> 

</object> 

</body> 
</html> 

的代理Servlet的源代碼如下:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 

    ServletContext context = getServletContext(); 
    PrintWriter out = null; 
    try { 
      String result = new String(); 
      String urlStr = request.getRequestURL().toString(); 


      URL url = new URL(urlStr); 
      URLConnection conn = url.openConnection(); 

      response.setContentType(conn.getContentType()); 

      if (conn.getContentType().contains("text/")) 
      { 
       out = response.getWriter(); 
       out.write(getTextContent(conn)); 
       out.flush(); 
       out.close(); 
      } 
      else 
      { 
       File file = new File("/var/www/final_lion.mov"); 
       response.setContentType("video/quicktime"); 
       response.setHeader("Content-Length", Long.toString(file.length())); 
       response.setHeader("Content-Disposition", "inline; filename=\"" + file.getName() + "\""); 
       FileInputStream input = new FileInputStream(file); 
       OutputStream output = response.getOutputStream(); 

       byte[] buffer = new byte[4096]; 
       int read = 0; 
       while((read = input.read(buffer)) != -1){ 
        output.write(buffer,0,read); 
       } 
       input.close(); 
       output.flush(); 
       output.close(); 

      } 
     } catch (Exception e) { 
       context.log("error", e); 
     } 
} 

private String getTextContent(URLConnection conn) 
{ 
    try{ 
     BufferedReader rd = new BufferedReader(new InputStreamReader(
       conn.getInputStream())); 
     StringBuffer sb = new StringBuffer(); 
     String line; 
     while ((line = rd.readLine()) != null) { 
      sb.append(line + "\n"); 
     } 
     rd.close(); 
     return sb.toString(); 
    }catch (Exception e){ 
     return "error: " + e.toString(); 
    } 
} 

HTML文檔由代理交付並由瀏覽器正確呈現。但GET請求的quicktime-video和代理的響應分別導致ClientAbortException:java.net.SocketException:斷開管道在servlet-sourcecode的第34行。我試過各種OutputStreams(BufferedOutputStream,DataOutputStream,PipedOutputStream,ServletOutputStream)。他們都沒有工作...

有沒有人看到我的錯誤?

此致, Ashiaka

+0

由於某種原因,客戶端可能會停止下載內容。 /var/www/final_lion.mov有多大?你能用小電影試試嗎? –

+0

final_lion.mov大小爲1 MB。我也嘗試了一個較小的視頻。這個問題也是一樣的。 – ashiaka

回答

2

玩家對於流媒體地塊預計在服務器端支持Range請求。通常servlet容器的(Tomcat,JBoss AS,Glassfish等)擁有默認的servlet已經支持。因此,如果有一種方法可以通過將文件夾添加到服務器配置中來將電影文件夾發佈到網絡中,以便您不需要本地servlet來完成此操作,那麼我會繼續使用此路線。如果你把final_lion.mov文件Tomcat/webapps/movies/var/www/movies文件夾

<Context docBase="/var/www/movies" path="/movies" /> 

例如,在Tomcat中,你可以通過只是將文件移動到Tomcat/webapps/movies文件夾實現這一目標,或通過添加下面的行其/conf/server.xml取決於配置選擇,那麼你應該可以通過http://localhost:8080/movies/final_lion.mov來訪問它,而不需要任何本地servlet。相反,Tomcat自己的DefaultServlet將用於流式傳輸靜態內容。

但是,如果沒有辦法,那麼您需要以支持Range請求(也稱爲下載簡歷)的方式重寫您的servlet代碼。您可以在this article中找到具體的開球示例。

+0

thx這個答案。我今天下午會嘗試。 – ashiaka

+0

偉大的文章!它的工作:) – ashiaka

+0

不客氣。 – BalusC

0

我面臨同樣的問題,花了幾天的時間,並試圖逐個挖掘。 這與您的瀏覽器緩存問題有關。您可以嘗試使用此代碼。這個對我有用。

response.addHeader(「Cache-Control」,「no-transform,max-age = 0」);

相關問題