2014-10-08 34 views
2

我必須使用Java套接字發送和接收HTTP請求(我必須!)。所以我正在尋找一個解決方案,考慮到content-lengthTransfer-Encoding: chunked等等,以決定HTTP請求何時結束。檢測HTTP請求(Java套接字)最簡單的方法?

這裏是什麼,我想出了到目前爲止的例子:

public String getWebpage() 
    { 
     try{ 

      _out.print("GET/HTTP/1.1\r\nHost: www.google.com\r\n\r\n"); 
      _out.flush(); 

      String fullRequest = ""; 
      String line = null; 
      while ((line = _in.readLine()) != null) 
      { 
       fullRequest += line + "\r\n"; 
       if(isFullRequest(fullRequest)) 
       { 
        System.out.println(fullRequest); 
        return fullRequest; 
       } 
      }    

     }catch(Exception e){} 

     return null; 
    } 

    private boolean isFullRequest(String request) 
    { 
     return request.contains("\r\n\r\n") //Make sure we have the headers 
      && request.contains("</html>"); //Make sure we have the html 
    } 

isFullRequest()方法是檢測請求結束一個非常廉價的方式,但並不可靠。我想知道是否已經有一個Class或Method已經包含在Java中,並且完全符合我的需求,而不是重新發明輪子並花費大量時間進行調試。沒有額外的不必要的jar依賴?

回答

4

如果您不想使用現有的HTTP庫,那麼只需要發出HTTP/1.0請求就容易得多,這樣您就不會得到分塊響應(chunked僅針​​對HTTP/1.1定義)。也不要使用keep-alive,這在HTTP/1.1中是隱含的,而不是在HTTP/1.0中使用。總之,請這樣做:

GET /page HTTP/1.0 
Host: hostname 

然後簡單地讀取響應,直到數據結束。由於keep-alive默認關閉HTTP/1.0,服務器將在響應完成後關閉連接,並且由於HTTP/1.0不支持分塊,所以您也不必擔心。

+0

謝謝!這種方式現在解決了我的問題,但也許它不是很可靠,因爲它可能會導致長期的一些問題..(如果有任何諸如HTTP/1.0服務器不兼容或機器人檢測或保護等等) – Heidi 2014-10-09 05:33:38

+1

如果你想看起來更像一個真正的瀏覽器,它更加複雜,因爲你不僅需要支持分塊的HTTP/1.1,而且還需要gzip和deflate內容編碼。即使這樣,由於缺少JavaScript,不會加載包括CSS,圖像,字體,不發送cookies等等資源,因此很容易區分您的請求和桌面瀏覽器。 – 2014-10-09 05:53:22

0

您可以使用HttpUrlConnection來讀取分塊響應。這樣您就不必擔心檢測請求的結束。

URL url = new URL(urlStr); 
HttpURLConnection uc = (HttpURLConnection)url.openConnection(); 
InputStream in = uc.getInputStream(); 
byte[] b=new byte[512*1024]; 
int len; 
OutputStream out = new FileOutputStream(f); 

while((len=in.read(b))!=-1){ 
    out.write(b,0,len); 
} 
out.flush(); 
out.close(); 
in.close(); 

如果你想要得到的內容lenght你可以試試:

long contentLength = uc.getContentLengthLong() 

它將只能如果content-length頭是已知的。

如果它是未知還有另一種方式(不是我最喜歡的,但...)。只讀一次流以瞭解內容長度。 我在一個需要下載頁面內容的時候需要繪製進度條的項目上使用它。

long max = uc.getContentLengthLong(); 
if(max==-1){ 
    max=0; 
    if(in.markSupported()){ 
     in.mark(1000000000); //max nb of bytes to be read 
     while((len=in.read(b))!=-1){ 
      max+=len; 
     } 
     in.reset(); 
    } 
}