HTTPサーバがデータに応答して考える

3183 ワード

HTTPサーバがデータに応答して考える
ソース
最近はネットのプログラミングに関する情報を勉強していますが、突発的に自分でhttp postを作ってデータを要求して会社のデータを要求します。
try {
    Socket socket = new Socket();
    socket.connect(new InetSocketAddress("...", 80)); //    host,   

    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

    writer.write("POST / HTTP/1.1\r
"); writer.write("Host: ...\r
"); // writer.write("User-Agent: Socket\r
"); writer.write("Accept: application/json\r
"); writer.write("Connection: close\r
"); writer.write("Content-Type: application/x-www-form-urlencoded\r
"); String body = "action=adv_index"; byte[] bytes = body.getBytes(); writer.write("Content-Length: " + bytes.length); writer.write("\r
"); writer.write("\r
"); writer.write(body); writer.flush(); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } writer.close(); reader.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); }
以下は取得した応答データです。
HTTP/1.1 200 OK
Server: nginx
Date: Sat, 27 Apr 2019 06:32:53 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: close
X-Powered-By: PHP/5.5.38
Access-Control-Allow-Origin: *

70c
//...        
0

最初はおかしいと思いましたが、なぜentity bodyの前後に文字列を追加しましたか?また他のインターフェースを要請しました。前の文字列が変わります。後ろの文字列は永遠に0です。
発見する
この応答データを注意深く観察した後、2つの点があることが分かりました。1.このpost応答ヘッダにはContent-Lengthがありません。2.この文字列はentity bodyの16進数長です。そこでいくつかの資料を検索しながらhttpプロトコルの内容を振り返ってみると、Transfer-Encodingというheaderが働いていることが分かりました。
http要求の長さ
ネットワーク要求は、一般的にコンテンツの終了を示す2つの方法があります。このようにデータを受け取る段階は、盲目的に待つ必要はありません。
  • は最初からコンテンツの長さを示していますが、httpは一般的にこのような方式を用いて、headerにContent-Lengthを使用して
  • を識別します。
  • は、コンテンツの前後に開始と終了の表示を追加し、ファイルを転送する場合、そのデータの前後に------の文字列表示の開始と終了を追加します。
    第一の方法は、データを伝送する前にその内容の長さを知っていますが、第二の方法は、データを伝送する前にコンテンツの長さを知らないときに採用されます。例えば、postを使ってファイルをアップロードする場合、Content-Typeに設定されたmultipart/form-dataは、boundaryの開始、パラメータ分割、終了を示すためにentity body属性を追加する。Transfer-Encodingはまた別の方法を採用しています。最初は内容の長さが分かりませんでした。もちろんContent-Lengthは使えません。この時、私達はもう一つの方法でコンテンツの境界を知る必要があります。Transfer-Encodingは一つのブロック分け方法を提供しています。コンテンツ全体の長さは分かりませんが、毎回送信されるコンテンツの長さは分かります。コンテンツ送信前に長さを追加します。
    具体的な方法
  • ヘッドにTransfer-Encoding: chunked
  • を追加します。
  • の各ブロックは16進数の長さ値を含み、この値は1ラインを独占し、長さはその後ろのCRLF(/r/n)を含まず、後のブロック内容のCRLF
  • も含まない。
  • の最後のブロックは0であると同時にブロックがありますが、ブロックにはコンテンツがありません。CRLF
  • だけです。
    重点
    したがって、Transfer-EncodingContent-Typeは共存しない。
    参照
    ブロック分けコード(Transfer-Enccoding:chunked)
    HTTPプロトコルにおけるContent-Lengthの詳細な解読。
    multiipad/form-data要求とファイルアップロードの詳細
    MultiiPad/form-data POSTファイルアップロード詳細