この記事について
この記事は、生成AIを活用した自動生成フローで作成しています。RFC 9112のHTTP/1.1メッセージ構造と.NETのTcpClient / NetworkStream APIを確認し、外部サイトへ接続しないlocalhost実験として実装しています。検証ステータス:📘 RFC・.NET公式API確認済み・localhostサンプル実装済み・PowerShell実機確認は未実施
PowerShellでHTTPを生で送ってみる ― TCPの上にHTTPが乗る感覚をlocalhostで確かめる
HTTPはTCPそのものではありません。HTTP/1.1では、TCP接続の上でrequest line、header fields、空行、必要ならbodyという形のメッセージをやり取りします。
普段は Invoke-WebRequest やブラウザが隠してくれる部分を、TcpClient へ文字列を直接書くと見えやすくなります。
今回は1台のPCだけで完結させる
外部Webサイトを実験台にせず、PowerShellを2つ開きます。
片方で
127.0.0.1:8085の簡易HTTPサーバーを起動もう片方でTCP接続
HTTP/1.1のGET requestを送信
サーバーが受信内容を表示
200 OKを返す
sequenceDiagram
participant C as PowerShell Client
participant T as TCP localhost:8085
participant S as PowerShell Server
C->>T: TCP connect
T->>S: connection accepted
C->>S: GET / HTTP/1.1 + headers + CRLF CRLF
S-->>C: HTTP/1.1 200 OK + headers + body
S-->>C: TCP close
送っているHTTPはただの文字列に見える
クライアント側の中心は次です。
$request = @(
"GET / HTTP/1.1"
"Host: localhost:8085"
"Connection: close"
""
""
) -join "`r`n"
$requestBytes = [System.Text.Encoding]::ASCII.GetBytes($request)
$stream.Write($requestBytes, 0, $requestBytes.Length)
$stream.Flush()
HTTP/1.1のrequest lineは GET / HTTP/1.1。その後ろにheader fieldsを続け、空行でheader sectionを終えます。
ここで "" を2つ並べて CRLF で結合しているのは、最後に CRLF CRLF を作るためです。
Host headerは省かない
RFC 9112ではHTTP/1.1 requestの Host header fieldを要求しています。教材だからといって GET / HTTP/1.1 だけ送ると、HTTP/1.1として重要な部分を隠してしまいます。
そこでlocalhost実験でも次を明示します。
Host: localhost:8085
TcpClientはHTTPを知らない
.NET の TcpClient はTCP接続を扱うクラスです。GetStream() で得た NetworkStream はbyte列を送受信します。
つまりこのコードでは、
flowchart TB
A[HTTPの文字列] --> B[ASCII bytes]
B --> C[NetworkStream]
C --> D[TCP]
D --> E[localhost server]
という層を自分で組み立てています。
この感覚がつかめると、HTTP client APIが「HTTPのルールに従ってメッセージを作り、その下でtransportを使っている」ことが理解しやすくなります。
レスポンスのContent-Lengthは文字数ではなくbyte数
サーバー側ではbodyをUTF-8へ変換してから Content-Length を作っています。
$body = "Hello from localhost HTTP over TCP`n"
$bodyBytes = [System.Text.Encoding]::UTF8.GetBytes($body)
$header = @(
"HTTP/1.1 200 OK"
"Content-Type: text/plain; charset=utf-8"
"Content-Length: $($bodyBytes.Length)"
"Connection: close"
""
""
) -join "`r`n"
Content-Length はoctet数なので、日本語などマルチバイト文字をbodyへ入れる場合に .Length の文字数をそのまま使わない点が重要です。
HTTPSはこのままではない
この教材は平文HTTPです。HTTPSではTCPの上にTLSを重ね、その上でHTTPをやり取りします。
HTTP TLS TCP IP
そのため、このサンプルを443番ポートへ向けてHTTP文字列だけ送っても、HTTPSの正しい通信にはなりません。次にTLSを学ぶときの入口として使えます。

コメント