2013-08-02 177 views
0

我正在嘗試構建自己的嵌入式HTTP服務器,用於Java,內部封閉系統的使用非常具體。使用已經存在的嵌入式解決方案意味着我需要剝離它們,以便爲我的內部系統的特定用例重新安裝它們。Java HTTP服務器響應不完整

我設法讓我的Java HTTPD接收來自Web瀏覽器的HTTP請求,但HTTPD接收的請求不完整。

下面是服務器線程代碼(假裝ServerSocket的工作完全正常):

public class HttpThread implements Runnable { 

    private Socket socket; 
    private DataInputStream in; 
    private PrintStream out; 
    private BufferedReader br; 
    private String EOF = "\n"; 
    private String STATUS_200 = "HTTP/1.1 200 OK" + EOF; 

    public HttpThread(Socket socket) throws IOException { 
     this.socket = socket; 
     this.in = new DataInputStream(this.socket.getInputStream()); 
     this.out = new PrintStream(new BufferedOutputStream(this.socket.getOutputStream())); 
    } 

    @Override 
    public void run() { 
     System.out.println("New thread..."); 
     try { 
      processInput(); 
      //socket.close(); 
     } catch (IOException ex) { 
      Logger.getLogger(HttpThread.class.getName()).log(Level.SEVERE, null, ex); 
     } finally { 
      if (br != null) { 
       try { 
        br.close(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
     //System.out.println("Thread END..."); 
    } 

    private String processInput() throws IOException { 
     String line; 
     StringBuilder buff = new StringBuilder(); 
     br = new BufferedReader(new InputStreamReader(in)); 
     while ((line = br.readLine()) != null) { 
      buff.append(line); 
      System.out.println(">>> " + line); 
      if (line.trim().isEmpty()) { 
       break; 
      } 
     } 
     out.print(STATUS_200); 
     out.print("Server: Test Server\n" + 
      "Content-Type: text/html; charset=UTF-8\n" + 
      "Connection: close"); 
     out.print(EOF); 
     out.print("<html><body>yello</body></html>"); 
     out.print(EOF); 
     out.flush(); 
     System.out.println(STATUS_200); 
     return buff.toString(); 
    } 

} 

我使用這個HTML腳本測試服務器線程模擬一個POST請求:

<html> 
<body onLoad="document.test.submit();"> 
<form action="http://localhost:9999/" method="POST" name="test"> 
    <input type=hidden name="userid" value="1443"/> 
    <input type=hidden name="password" value="1443"/> 
</form> 
</body> 
</html> 

當我使用瀏覽器調用HTML代碼時,Java HTTPD收到不完整的響應:

New thread... 
>>> POST/HTTP/1.1 
>>> Host: localhost:9999 
>>> Connection: keep-alive 
>>> Content-Length: 25 
>>> Cache-Control: max-age=0 
>>> Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
>>> Origin: null 
>>> User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.72 Safari/537.36 
>>> Content-Type: application/x-www-form-urlencoded 
>>> Accept-Encoding: gzip,deflate,sdch 
>>> Accept-Language: en-GB,en-US;q=0.8,en;q=0.6 
>>> 
HTTP/1.1 200 OK 

New thread... 
>>> GET /favicon.ico HTTP/1.1 
>>> Host: localhost:9999 
>>> Connection: keep-alive 
>>> Accept: */* 
>>> User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.72 Safari/537.36 
>>> Accept-Encoding: gzip,deflate,sdch 
>>> Accept-Language: en-GB,en-US;q=0.8,en;q=0.6 
>>> 
HTTP/1.1 200 OK 

看來,HTTPD只接收到HTTP頭並停止接收POST正文。 我可以知道一些解決方案來解決上述問題嗎?

謝謝。

回答

0

我切換出while循環用下面的代碼執行的ReadLine():

int i; 
byte[] buffer = new byte[2048]; 
i = in.read(buffer); 
for (int j = 0; j < i; j++) { 
    buff.append((char) buffer[j]); 
} 
System.out.println(buff.toString()); 

和問題解決。

Pyranja,感謝您的幫助。

感謝http://kcd.sytes.net/articles/simple_web_server.php如果您遵循簡潔。不知何故,br.readline()在空行之後沒有完全正確地讀取行。

的代碼片段現在應該是這樣的:

private String processInput() throws IOException { 
     String line; 
     StringBuilder buff = new StringBuilder(); 
     int i; 
     byte[] buffer = new byte[2048]; 
     i = in.read(buffer); 
     for (int j = 0; j < i; j++) { 
      buff.append((char) buffer[j]); 
     } 
     System.out.println(buff.toString()); 
     out.print(STATUS_200); 
     out.print("Server: Test Server\n" + 
      "Content-Type: text/html; charset=UTF-8\n" + 
      "Connection: close"); 
     out.print(EOF); 
     out.print("<html><body>yello</body></html>"); 
     out.print(EOF); 
     out.flush(); 
     System.out.println(STATUS_200); 
     return buff.toString(); 
} 

我想這是一個很好的經驗,學習如何建立一個簡單的HTTP服務器:d。

2

HTTP標題和正文由行(also see the HTTP RFC,特別是章節「5請求」)分隔。你的服務器讀取插座Inputstream但休息的空行:

if (line.trim().isEmpty()) { 
    break; 
} 

因此很明顯,你將不會收到身體。您應該完全消耗Inputstream

除此之外,我建議您使用已有的解決方案。有大量的HTTP服務器實現,經過了充分的測試,並在現實世界中得到了驗證。節省很多頭痛,並使用現有的輕量級服務器,例如碼頭,Netty或類似的。

+0

這些輕量級服務器容易拆卸嗎?我需要把它們拆下來,因爲內部服務器我的環境需要很多定製功能。最好是一個僞HTTP服務器。 – thotheolh

+0

Jetty是一個ServletEngine,如果你可以在一個Servlet中實現你的自定義功能(或者爲ReSTful服務提供JAX-RS),它將是一個不錯的選擇。 Netty更低級別,引用了[網頁](http://www.netty.io),它是一個服務器/客戶端框架。它支持爲任意協議編寫網絡代碼。 – Pyranja

+0

我刪除了「break」並且服務器連接只是簡單地循環並等待,直到我去瀏覽器點擊停止按鈕,並且請求主體終於通過了。 – thotheolh