web-dev-qa-db-ja.com

ソケット経由でHTTP要求を手動で送信する

ソケットを介して通常のHTTP要求を送信すると、サーバーはOK応答で応答しません。 FireFoxから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要求を識別しないのはなぜですか?

47
Eng.Fouad

2つのこと:

  1. エントリを別の行に出力するには、printlnの代わりにprintを使用する必要があります。
  2. HTTPリクエストは空白行で終了する必要があります( link )。 pw.println("");を追加します
46
Lycha

HTTP RFC に従っていません。

  • ヘッダー行は常にCR LF(つまり、0x0d plus 0x0a)。
  • ヘッダーは最初の二重改行の後に終了します。あなたの場合、サーバーがリクエストヘッダーの終わりを認識しないように、末尾の改行を含めないでください。

通常、既存のHTTPライブラリを常に使用するようにしてください。 HTTPは単純なプロトコルのように思われますが(他のプロトコルと比較されます)、かなり厳格な構文規則と意味規則を持っています。これを自分で実装しようとする場合は、RFC 2616(および関連する)の​​関連部分を読んで理解しておく必要があります。

残念なことに、すでに標準に準拠していないくだらないHTTP実装が多すぎて、すべての人の命を惨めなものにしています。手間を省いて、選択した言語のHTTPライブラリを使用してください。

22
Holger Just

実際に動作し、クロスプラットフォームである正しい修正:

    pw.print("GET / HTTP/1.1\r\n");
    pw.print("Host: stackoverflow.com\r\n\r\n");
8
TadejP

前の回答で述べたように、次の修正は問題を解決します。

pw.print("GET / HTTP/1.1\n\r\n");
pw.print("Host: stackoverflow.com\n\r\n");
4
Aimar Hassano