【问题标题】:Java socket gets HTTP/1.1 400 Bad RequestJava 套接字获取 HTTP/1.1 400 错误请求
【发布时间】:2017-03-17 07:01:30
【问题描述】:

从this question 尝试了此代码。当只是请求stackoverflow.com 时,它会给出正确的回复,但是当我尝试https://stackoverflow.com/questions/10673684/send-http-request-manually-via-socket 时,它会返回HTTP/1.1 400 Bad Request。是什么导致了这个问题?

这是我从上面的链接得到的工作代码,它给出了来自服务器的正确响应。

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

尝试将其更改为以下...

Socket s = new Socket(InetAddress.getByName("stackoverflow.com"), 80);
PrintWriter pw = new PrintWriter(s.getOutputStream());
pw.println("GET / HTTP/1.1");
pw.println("Host: https://stackoverflow.com/questions/10673684/send-http-request-manually-via-socket");
pw.println("");
pw.flush();
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String t;
while ((t = br.readLine()) != null) {
    System.out.println(t);
}

那么回复是HTTP/1.1 400 Bad Request。

附:我不打算使用任何 http 库。

【问题讨论】:

  • 主机应该保持在工作代码中,但您必须将主机上方的行更改为GET /questions/10673684/send-http-request-manually-via-socket HTTP/1.1
  • @Alex 您应该将该评论作为答案
  • 嗨@Alex。你说的对。太感谢了。如果你要回答我会标记它。
  • 另外你应该使用\r\n作为行尾而不是\n并且你不应该期望服务器在响应之后关闭连接,因为你已经通过使用HTTP版本隐式请求持久连接1.1。出于同样的原因,您还需要能够处理数据的分块传输编码。建议在实现协议时查看适当的标准,而不仅仅是猜测行为。

标签: java sockets


【解决方案1】:

问题在于您的请求,这是不正确的。如果您将调用 PrintWriter 替换为

pw.println ("GET /questions/10673684/send-http-request-manually-via-socket HTTP/1.1");
pw.println ("Host: stackoverflow.com");

它应该工作。


编辑: 正如 EJP 在对此答案的评论中指出的那样,您应该确保行尾始终为 \r\n。您可以放弃 println 函数,而是使用

pw.print ("Host: stackoverflow.com\r\n");

或you could change the default line ending to make sure println works correctly,但是,这也可能影响您程序的其他部分。


此外,您可以使用 try-with-resources 来确保在您完成阅读后关闭您的套接字,这解决了 Steffen Ullrichs 在他对您的问题的评论中所关注的问题之一。

但是,在您的第一个示例中,您调用br.close();,它应该关闭底层输入流,进而关闭套接字,所以它也应该工作。但是,在我看来,最好明确地这样做。

【讨论】:

  • 除非您至少修复线路终止,否则不会使用println(),这是不的问题。您可能会很幸运拥有一系列宽容的 HTTP 服务器,但任何 HTTP 服务器都有权仅基于此忽略/拒绝请求。
  • 我试图在我的编辑中解决您的问题。如果需要,您仍然可以使用println(),您只需在创建 PrintWriter 实例之前设置 line.separator 属性。
  • 如果我没有亲眼看到来自 Apache 的 400 Bad Request,我不会相信docs.oracle.com/javase/10/security/… 的 SSLSocketClient.java 示例代码也缺少您的 \r 洞察力。 Sun/Oracle 只在 Windows 上测试过?强者如何堕落!
猜你喜欢
  • 1970-01-01
  • 2017-07-21
  • 1970-01-01
  • 2015-04-10
  • 2022-11-25
  • 2023-03-11
  • 1970-01-01
  • 2014-10-24
  • 1970-01-01
相关资源
最近更新 更多