当前位置: 代码迷 >> java >> 接收http请求时,简单的Web服务器挂起
  详细解决方案

接收http请求时,简单的Web服务器挂起

热度:12   发布时间:2023-07-17 20:44:28.0

我正在写一个简单的Web服务器,代码片段:

 ServerSocket server = new ServerSocket(80);  
  Socket client=server.accept();  
  InputStream in=client.getInputStream();  
  OutputStream out=client.getOutputStream();  
  int val = -1;  
  while ((val = in.read()) != -1) {  
    System.out.print((char) val);  
  }   
  BufferedWriter writer = new BufferedWriter(new OutputStreamWriter( out));  
  writer.write("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\nhello world!");  
  writer.close();  
  out.close();  
  in.close();

我在我的电脑上运行它,然后在Firefox中访问 。 页面挂起,无法显示“hello world”。我认为问题发生在while ((val = in.read()) != -1) ,如何解决?

HTTP(至少1.1版本)允许打开连接。 然后请求以空行结束(即"\\r\\n\\r\\n" ),如果它不是带有内容的POST或PUT请求。 在此之后,客户端可以在同一连接上发送下一个请求。

因此,您必须至少读取输入以扫描空行。


编辑:为了澄清这一点,来自 (定义HTTP 1.1)的一些引用。

部分4.1,消息类型

请求(第5节)和响应(第6节)消息使用RFC 822 [9]的通用消息格式来传输实体(消息的有效载荷)。 两种类型的消息都包括一个起始行,零个或多个标题字段(也称为“标题”),一个空行(即CRLF前面没有任何内容的行),表示标题字段的结尾,可能还有一个邮件正文。

  generic-message = start-line *(message-header CRLF) CRLF [ message-body ] start-line = Request-Line | Status-Line 

因此,消息头和消息体由空行(起始行之后的第一个)分隔。

4.3消息正文

HTTP消息的消息体(如果有的话)用于携带与请求或响应相关联的实体体。 [...]

消息中允许消息正文的规则因请求和响应而异。

通过在请求的消息头中包含Content-Length或Transfer-Encoding头字段来指示请求中消息体的存在。 如果请求方法的规范(第5.1.1节)不允许在请求中发送实体主体,则消息主体不得包含在请求中。 服务器应该在任何请求上读取和转发消息体; 如果请求方法不包含实体主体的定义语义,那么在处理请求时应该忽略消息主体。

因此原则上,客户端必须只在方法允许时发送一个正文,但是服务器应该忽略多余的消息体,如果它们是在不支持它的方法上发送的。 并且Content-LengthTransfer-Encoding头字段指示正文的存在。

第9节的小节定义了各个方法。

  • 9.2选项
    • 可以包含一个正文,但意义没有定义
  • 9.3 GET
    • 不能包含任何身体
  • 9.4头
    • 不能包含任何身体
  • 9.5 POST
    • 应该(或必须?)包含一个身体
  • 9.6 PUT
    • 应该(或必须?)包含一个身体
  • 9.7删除
    • 不能包含任何身体
  • 9.8追踪
    • 不能包含任何身体
  • 9.9连接
    • (此方法保留)

无论如何,无论客户端是否发送正文,以及它是否重新使用连接以进行下一个请求,通常都不会在读取响应之前关闭连接,否则您的服务器根本无法重新发送响应。 因此,您在阅读请求时无法等待结束,但必须以某种方式知道何时结束发送您的回复。

对于只处理获取请求的简单hello world服务器,您可以简单地说“直到第一个空行”。

对于真实的服务器(即外部世界可见的服务器),您至少应该解析请求,忽略任何正文,并以不同于GET的方式处理HEAD(即,不发送任何正文),并发送错误响应不支持的方法。

  相关解决方案