2014-10-08 35 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(); 
    } 
}