Node.jsがサーバーサイドのJavaScript実行環境として広く普及した現代においても、その基幹を支える「httpモジュール」の重要性は揺らぎません。
ExpressやNestJSといった高度なフレームワークが主流となっている2026年現在でも、プロトコルの低レイヤーを理解することは、システムの最適化やトラブルシューティングにおいて極めて重要なスキルとなります。
本記事では、Node.jsの標準機能であるhttpモジュールを用い、シンプルかつ堅牢なサーバーを構築するための基礎知識から実践的なテクニックまでを詳しく解説します。
httpモジュールの役割と基本構造
httpモジュールは、Node.jsでHTTPサーバーおよびクライアントを実装するための標準ライブラリです。
このモジュールはNode.jsのイベントループと密接に連携しており、非同期I/Oを活用した高効率な通信を実現します。
標準ライブラリであるため、外部のパッケージをインストールすることなく軽量なネットワークアプリケーションを作成できるのが大きな利点です。
また、httpモジュールは低レイヤーの操作を提供するため、ヘッダーの細かな制御やストリーム処理を自由に行うことが可能です。
現代のWeb開発ではフレームワークの内部で動作していることが多いですが、その仕組みを知ることで、フレームワークの限界を超えたカスタマイズが可能になります。
HTTPサーバーの最小構成
まずは、httpモジュールを使用して最も基本的なWebサーバーを作成する方法を確認しましょう。
サーバーを作成するには、http.createServer()メソッドを使用します。
// httpモジュールの読み込み
const http = require('http');
// サーバーオブジェクトの作成
const server = http.createServer((req, res) => {
// レスポンスヘッダーの設定
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
// ボディの書き込みと終了
res.end('Node.jsサーバーが正常に起動しました。\n');
});
// 3000番ポートで待機を開始
const PORT = 3000;
server.listen(PORT, () => {
console.log(`Server is running at http://localhost:${PORT}/`);
});
Server is running at http://localhost:3000/
上記のコードでは、リクエストを受け取るたびにコールバック関数が実行され、レスポンスが返されます。
createServerのコールバックには、リクエストを管理するオブジェクトとレスポンスを制御するオブジェクトの2つが渡されます。
server.listen()を呼び出すことで、指定したポート番号で接続を待ち受ける状態になります。
IncomingMessageとServerResponseの理解
httpモジュールの中心となるのは、IncomingMessageとServerResponseという2つのクラスです。
IncomingMessageはクライアントからのリクエスト情報を保持しており、URL、メソッド、ヘッダーなどが含まれます。
一方、ServerResponseはサーバーからクライアントへ送信するデータを制御するためのオブジェクトです。
主なプロパティとメソッドを以下の表にまとめました。
| オブジェクト | 主なプロパティ・メソッド | 説明 |
|---|---|---|
| req (IncomingMessage) | req.url | リクエストされたURLのパスを取得します。 |
| req (IncomingMessage) | req.method | GET、POST、PUTなどのHTTPメソッドを取得します。 |
| req (IncomingMessage) | req.headers | 送信されたHTTPヘッダーを含むオブジェクトです。 |
| res (ServerResponse) | res.writeHead() | ステータスコードとヘッダーを一括で送信します。 |
| res (ServerResponse) | res.write() | レスポンスボディの一部を送信します。 |
| res (ServerResponse) | res.end() | レスポンスの送信を完了します。 |
これらのプロパティを適切に組み合わせることで、複雑なロジックを実装することができます。
特にreq.urlとreq.methodの組み合わせは、ルーティングを自作する際の基礎となります。
ルーティングとステータスコードの処理
実用的なサーバーでは、リクエストされたURLのパスに応じて処理を分岐させる必要があります。
httpモジュール単体でルーティングを行う場合は、if文やswitch文を使用してパスを判定します。
const http = require('http');
const server = http.createServer((req, res) => {
const path = req.url;
if (path === '/' && req.method === 'GET') {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end('<h1>ホーム画面</h1>');
} else if (path === '/about' && req.method === 'GET') {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end('<h1>サイトについて</h1>');
} else {
// 404 Not Found の処理
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('ページが見つかりません。');
}
});
server.listen(4000);
このように、URLのパスに応じて適切なステータスコードを返すことが重要です。
ステータスコード 200 は成功、404 はリソース未発見、500 はサーバー内部エラーを意味します。
適切なエラーハンドリングを行うことで、クライアント側に不具合の原因を正確に伝えることができます。
POSTデータの受信と解析
HTTPサーバーにおいて、クライアントから送信されたデータを取得する処理は頻繁に発生します。
Node.jsのhttpモジュールでは、リクエストボディは「ストリーム」として扱われます。
そのため、データが大きな場合には複数回に分けて受信されることがあるため、イベントリスナーを使用してデータを組み立てる必要があります。
const http = require('http');
const server = http.createServer((req, res) => {
if (req.method === 'POST') {
let body = '';
// データの一部を受信するたびに発生するイベント
req.on('data', chunk => {
body += chunk.toString();
});
// 全データの受信が完了したときに発生するイベント
req.on('end', () => {
console.log('受信データ:', body);
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: '受信完了', receivedData: body }));
});
}
});
server.listen(5000);
このコードでは、dataイベントでチャンク(データの断片)を取得し、変数bodyに結合しています。
全てのデータが到着した時点でendイベントが発生し、そこではじめて受信したデータを処理できます。
JSON形式のデータを扱う場合は、JSON.parse(body)を使用してJavaScriptのオブジェクトに変換して利用します。
JSON APIの構築と実践的なレスポンス
現代のWebアプリケーションにおいて、サーバーはHTMLを返すだけでなく、JSON形式のAPIサーバーとして機能することが一般的です。
httpモジュールを使用してAPIを構築する際は、ヘッダーに'Content-Type': 'application/json'を指定します。
また、CORS(Cross-Origin Resource Sharing)の設定が必要になることも多いでしょう。
const http = require('http');
const server = http.createServer((req, res) => {
// CORS対応のヘッダー設定
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
if (req.method === 'OPTIONS') {
res.writeHead(204);
res.end();
return;
}
if (req.url === '/api/user' && req.method === 'GET') {
const userData = { id: 1, name: 'Node Taro', year: 2026 };
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(userData));
}
});
server.listen(8080);
OPTIONSメソッドへの対応は、ブラウザからのプリフライトリクエストを正常に処理するために必要です。
このように、低レイヤーのhttpモジュールでは、ヘッダーの一つひとつを手動で設定することで、自由度の高いAPI開発が可能になります。
セキュリティとパフォーマンスの考慮
2026年のWeb環境において、サーバーのセキュリティ対策は無視できません。
httpモジュールを直接使用する場合、いくつかのセキュリティヘッダーを自前で追加することが推奨されます。
- X-Content-Type-Options: nosniff (MIMEタイプのスニッフィングを防止)
- X-Frame-Options: DENY (クリックジャッキング対策)
- Strict-Transport-Security (HTTPS通信を強制)
また、パフォーマンス面では、Keep-Aliveの設定やストリーミングを活用することで、効率的なデータ配送が可能になります。
大きなファイルを配信する場合は、fs.createReadStream()とres.pipe()を組み合わせることで、メモリ消費を最小限に抑えることができます。
メモリ効率を考慮した設計は、大量の同時接続をさばくNode.jsサーバーにおいて極めて重要です。
まとめ
Node.jsのhttpモジュールは、Webサーバー構築におけるもっとも根幹的なツールです。
リクエストとレスポンスの流れを正しく理解し、適切なステータスコードやヘッダーを扱うことで、フレームワークに頼らない柔軟なサーバー構築が可能になります。
本記事では基礎的なサーバーの起動から、ルーティング、POSTデータの受信、そしてAPI構築における留意点までを網羅しました。
これらの知識を土台にすることで、Expressなどのライブラリをより深く理解し、使いこなすことができるようになるでしょう。
まずはシンプルなサーバーの構築から始め、Node.jsの強力なネットワーク機能を体感してみてください。
