2013-08-02 165 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