Node.jsは、サーバーサイドでJavaScriptを実行できるランタイム環境として、現代のWeb開発において不可欠な存在となりました。

大量の同時接続を効率的に処理できる非同期I/Oモデルを採用しているため、リアルタイム性が求められるアプリケーションやスケーラビリティが重視されるシステムに最適です。

本記事では、Node.jsを使用してWebサーバーを構築する手順を、基礎知識から具体的な実装コードまで詳しく解説します。

Node.jsの基本構造とWebサーバーの仕組み

Node.jsでWebサーバーを作る前に、その内部的な仕組みを理解しておくことは非常に重要です。

一般的なWebサーバーはリクエストごとにスレッドを生成しますが、Node.jsは「シングルスレッド・イベントループ」という方式を採用しています。

これにより、メモリ消費を抑えながら大量のリクエストを高速に捌くことが可能になっています。

また、Node.jsはGoogle Chromeでも使用されているV8エンジンを搭載しており、JavaScriptを高パフォーマンスで実行できるのが特徴です。

サーバーサイドでJavaScriptを使用できることで、フロントエンドとバックエンドの言語を統一できるという大きなメリットがあります。

イベント駆動型アーキテクチャの利点

Node.jsの最大の特徴は、イベント駆動型アーキテクチャにあります。

これは、何らかのアクション(リクエストなど)が発生した際に、あらかじめ登録しておいた処理(コールバック関数)を呼び出す仕組みです。

I/O処理の完了を待たずに次の処理へ移ることができるため、ノンブロッキングな通信を実現しています。

この仕組みにより、データベースへの問い合わせやファイル読み込みなどの重い処理を行っている間も、他のユーザーからのリクエストを受け付けることができます。

環境構築:Node.jsのインストールとプロジェクト初期化

まずは、Webサーバーを開発するための準備を整えていきましょう。

Node.jsがインストールされていない場合は、公式サイトから推奨版(LTS)をダウンロードしてインストールしてください。

インストールが完了したら、ターミナル(またはコマンドプロンプト)で以下のコマンドを入力し、バージョンが表示されるか確認します。

Shell
node -v
npm -v
実行結果
v24.x.x
10.x.x

次に、プロジェクト用のディレクトリを作成し、初期化処理を行います。

npm init -yを実行することで、プロジェクトの構成を管理するpackage.jsonファイルが生成されます。

Shell
mkdir my-web-server
cd my-web-server
npm init -y

最近のNode.js開発では、CommonJS形式(require)よりもES Modules形式(import/export)が主流です。

package.json"type": "module"という記述を追加することで、最新のJavaScript構文を標準で使用できるようになります。

標準モジュール「http」を使用した最小構成のサーバー構築

Node.jsには、外部ライブラリをインストールしなくてもWebサーバーを作成できるhttpモジュールが標準で備わっています。

まずは、最もシンプルなWebサーバーを作成して、ブラウザに「Hello World」を表示させてみましょう。

index.jsというファイルを作成し、以下のコードを記述してください。

JavaScript
// httpモジュールをインポート
import http from 'http';

// サーバーオブジェクトを作成
const server = http.createServer((req, res) => {
  // レスポンスヘッダーの設定(ステータスコード200、コンテンツタイプをテキストに指定)
  res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
  
  // ボディの内容を書き込み
  res.end('Node.js Webサーバーへようこそ!\n');
});

// ポート3000でリクエストを待機
const PORT = 3000;
server.listen(PORT, () => {
  console.log(`サーバーが起動しました: http://localhost:${PORT}`);
});

コードを記述したら、ターミナルでnode index.jsを実行します。

実行結果
サーバーが起動しました: http://localhost:3000

ブラウザでhttp://localhost:3000にアクセスし、指定したメッセージが表示されれば成功です。

http.createServerメソッドの引数に渡されるコールバック関数は、リクエストがあるたびに実行される重要な部分です。

人気フレームワーク「Express」を活用した開発

標準のhttpモジュールだけでもサーバーは作れますが、大規模なアプリケーションを作る場合には記述が煩雑になります。

そこで、Node.jsで最も普及しているWebフレームワークである「Express」を使用するのが一般的です。

Expressを利用することで、ルーティング(URLごとの処理分け)やテンプレートエンジンの利用、ミドルウェアの管理が飛躍的に簡単になります。

Expressの導入手順

まず、npmを使用してExpressパッケージをプロジェクトにインストールします。

Shell
npm install express

インストールが完了したら、Expressを使用してWebサーバーを書き換えてみましょう。

以下のコードは、Expressを用いた基本的なサーバーの構成例です。

JavaScript
import express from 'express';

const app = express();
const PORT = 3000;

// ルートパス(/)へのアクセスに対する処理
app.get('/', (req, res) => {
  res.send('これはExpressで構築されたサーバーです。');
});

// サーバーの起動
app.listen(PORT, () => {
  console.log(`Expressサーバーが起動しました: http://localhost:${PORT}`);
});

標準モジュールに比べ、コードが非常にシンプルで読みやすくなっていることが分かります。

ルーティングの実装

Webサーバーでは、アクセスされるURL(パス)に応じて異なるコンテンツを返す必要があります。

Expressでは、app.get()app.post()といったメソッドを使って、簡単にルーティングを定義できます。

JavaScript
// プロフィールページ
app.get('/profile', (req, res) => {
  res.send('プロフィールページです。');
});

// お問い合わせページ
app.get('/contact', (req, res) => {
  res.send('お問い合わせページです。');
});

このようにパスごとに処理を分割することで、Webサイトの構造を整理して記述できます。

JSONレスポンスの返却

現代のWeb開発、特にSPA(Single Page Application)やモバイルアプリのバックエンドでは、HTMLではなくJSONデータを返すことが増えています。

Expressでは、res.json()メソッドを使用するだけで、JavaScriptのオブジェクトを自動的にJSON形式に変換して送信できます。

JavaScript
app.get('/api/user', (req, res) => {
  const userData = {
    id: 1,
    name: '田中太郎',
    role: 'エンジニア'
  };
  res.json(userData);
});

これにより、APIサーバーとしての構築も非常に容易に行うことが可能です。

実践的なWebサーバーへの拡張

基本的なサーバーが動作するようになったら、次はより実践的な機能を追加していきましょう。

実際のWeb運用では、静的ファイルの配信やエラーハンドリング、非同期処理の制御などが欠かせません。

ミドルウェアの活用

Expressの強力な機能の一つに「ミドルウェア」があります。

ミドルウェアとは、リクエストを受け取ってからレスポンスを返すまでの間に実行される共通処理のことです。

例えば、画像やCSSファイルなどの静的ファイルを公開するには、express.staticミドルウェアを使用します。

JavaScript
// 'public'ディレクトリ内のファイルを静的ファイルとして公開
app.use(express.static('public'));

また、ログを出力したり、リクエストボディを解析したりするためのミドルウェアも多く存在します。

非同期処理の実装

Node.jsの強みを活かすためには、async/awaitを用いた非同期処理の理解が不可欠です。

データベースへのアクセスや外部APIの呼び出しは時間がかかるため、非同期で処理を行うことでサーバー全体のパフォーマンスを維持できます。

JavaScript
import fetch from 'node-fetch'; // 外部API呼び出し用のライブラリ

app.get('/external-data', async (req, res) => {
  try {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    res.json(data);
  } catch (error) {
    res.status(500).send('データ取得に失敗しました。');
  }
});

try-catch構文を併用することで、エラーが発生した際の例外処理も安全に記述できます。

運用を見据えたセキュリティとパフォーマンス

サーバーを公開する際には、セキュリティ対策やパフォーマンスの最適化も考慮しなければなりません。

Node.jsには、これらをサポートする便利なツールが数多く提供されています。

対策項目推奨ツール・手法内容
HTTPヘッダー保護Helmet.jsセキュリティ関連のHTTPヘッダーを適切に設定する。
プロセス管理PM2アプリがクラッシュした際の自動再起動や負荷分散を行う。
環境変数の管理dotenvAPIキーやポート番号などの機密情報を外部ファイルで管理する。
入力値の検証express-validatorユーザーからの入力データが正しい形式かチェックする。

特にHelmet.jsは、クロスサイトスクリプティング(XSS)などの一般的な攻撃を防ぐために、導入が強く推奨されます。

また、商用環境では単一のプロセスで実行するのではなく、PM2などのツールを使用してマルチコアを有効活用する構成が一般的です。

まとめ

Node.jsを使用したWebサーバー構築は、標準モジュールだけでも可能ですが、Expressなどのフレームワークを活用することで開発効率が大幅に向上します。

JavaScriptという一つの言語でフロントエンドからバックエンドまで一貫して開発できる点は、エンジニアにとって非常に大きなアドバンテージです。

まずは、ローカル環境でシンプルなサーバーを動かすことから始め、徐々にルーティングやミドルウェア、データベース連携へとステップアップしていきましょう。

セキュリティ対策や非同期処理の適切な実装を学ぶことで、実運用にも耐えうる堅牢なシステムを構築できるようになります。

Node.jsの持つ高いスケーラビリティを活かし、モダンで高速なWebアプリケーション開発にぜひ挑戦してみてください。