2012-05-20 86 views
37

當我通過一個套接字發送一個正常的HTTP請求時,服務器不響應一個OK響應。我複製了FireFox的HTTP標頭。下面是代碼:通過套接字手動發送HTTP請求

Socket s = new Socket(InetAddress.getByName("stackoverflow.com"), 80); 
PrintWriter pw = new PrintWriter(s.getOutputStream()); 
pw.print("GET/HTTP/1.1"); 
pw.print("Host: stackoverflow.com"); 
pw.flush(); 
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream())); 
String t; 
while((t = br.readLine()) != null) System.out.println(t); 
br.close(); 

然而,這裏是我收到的迴應:

HTTP/1.0 408 Request Time-out 
Cache-Control: no-cache 
Connection: close 
Content-Type: text/html 

<html><body><h1>408 Request Time-out</h1> 
Your browser didn't send a complete request in time. 
</body></html> 

我知道,我可以用URL.openStream()做到這一點,但爲什麼服務器不識別的HTTP請求當我手動發送它?

+3

我想你把所有的報頭之後發送一個額外的換行; 'pw.println();',並且使用'println()'作爲頭文件? – Torious

+0

@Torious是的,這就是問題所在。謝謝:) –

+1

對於HTTP,換行符必須是\ r \ n的格式。 – EJP

回答

37

兩件事情:

  1. 您應該使用println而不是print打印您的條目來分隔行。
  2. HTTP請求應以空行結束(link)。因此,請添加pw.println("");
+0

完美。添加空白行很重要! – asgs

+1

這隻適用於Windows機器。在Linux上,它只會打印LF而不是HTTP規範所需的CRLF。查看其他答案。 – Xiv

+0

當我將主機改爲'pw.println(「Host:httpstackoverflow.com/questions/10673684/send-http-request-manually-via-socket」)時,它爲什麼會給出'HTTP/1.1 400 Bad Request'? 「 – beginner

19

您不遵循HTTP RFC

  • 標題行總是以CR LF結尾(即0x0d0x0a)。
  • 標題在第一個雙換行符後結束。在你的情況下,你不包括尾隨的換行符,所以服務器不能識別請求頭的末尾。

通常,您應該總是嘗試使用現有的HTTP庫。儘管HTTP似乎是一個簡單的協議(並且與其他協議相比),但它具有相當嚴格的語法和語義規則。如果您嘗試自己實現這一點,則應該閱讀並理解RFC 2616(及相關)的相關部分。

不幸的是,已經有太多蹩腳的HTTP實現不遵循標準,使每個人的生活都很悲慘。省去麻煩並使用所選語言的HTTP庫。

+1

+1」是爲了讓\ r \ n部分正確。 – EJP

4

正如前面的答案所述,下列修復解決了問題;

pw.print("GET/HTTP/1.1\n\r\n"); 
pw.print("Host: stackoverflow.com\n\r\n"); 
8

正確的修復,其真正起作用的,它是跨平臺:

pw.print("GET/HTTP/1.1\r\n"); 
    pw.print("Host: stackoverflow.com\r\n\r\n"); 
+0

我使用'Host:'而不是'Host:'並且所有的錯誤請求都是(400),花了一天的時間才意識到,它真的很糟糕。 – 2016-07-29 06:08:37