2012-05-20 87 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