Express によるサーバー構築
ウェブサイトが動作する仕組み
「Web プログラミングの基礎を学ぼう」 の章では、ウェブサイトを表示するために HTML ファイルと JavaScript ファイルを作成し、ブラウザから開きました。 しかし、一般的なウェブサイトを閲覧する際は、HTML ファイルや JavaScript ファイルの存在を意識することはありません。 これは、Web では、通常インターネットを介してデータをやり取りするため です。
インターネットを人間が直接利用することはできないので、何らかのコンピューターを使用しなければなりません。 このとき、
- クライアント: サービスを利用する側のコンピューターや、その上で直接通信を担うソフトウェア
- サーバー: サービスを提供する側のコンピューターや、その上で直接通信を担うソフトウェア
という二者の関係が発生します。また、その間で発生する通信を、その方向により
- リクエスト: クライアントからサーバーに対する要求
- レスポンス: リクエストに対するサーバーからクライアントへの応答
のように区別して呼びます。
Google Chrome や Safari に代表されるブラウザは、Web におけるクライアントソフトウェアの呼称です。 Web において、HTML、CSS、JavaScript は、サーバーがクライアントに対してレスポンスとして送信するデータの一部で、ブラウザによって解釈されて表示されます。
ここからは、Node.js を用いて、Web サーバーとして動作するソフトウェアを作成していきます。
ブラウザは、サーバーと通信して取得した HTML、CSS、JavaScript データを解釈して表示するだけでなく、コンピューター上にファイルの形式で存在している HTML、CSS、JavaScript を表示することもできます。 ここまでの教材では、サーバーという概念の導入による複雑さを避けるため、この機能を用いて各言語の文法を学んできました。
Express パッケージを用いて Web サーバーを構築する
Express パッケージ を用いると、簡単に Web サーバーを構築できます。
まずは express
パッケージを npm でインストールします。
npm install express
続いて、次のような main.mjs
を作成しましょう。
import express from "express";
const app = express();
app.get("/", (request, response) => {
response.send(`Hello World! <a href="./lang/ja">日本語</a>`);
});
app.get("/lang/ja", (request, response) => {
response.send("こんにちは、世界!");
});
app.listen(3000);
ファイルを保存したら、作成したファイルを実行しましょう。
node main.mjs
ブラウザで http://localhost:3000/
にアクセスし、次の動作を確認してください。
Hello World! 日本語
が表示される こと日本語
をクリックするとアドレスバーがhttp://localhost:3000/lang/ja
に変化しこんにちは、世界!
が表示されること
サーバーは、クライアントからのリクエストを待ち受けるため、管理者により指示されない限り終了しないソフトウェアとして動作します。 Express で構築したサーバーは、ターミナル上で control + C (macOS) / Ctrl + C (Windows) を押すことで停止することができます。
HTTP と URL
前項のプログラムが動作する仕組みを理解するためには、ブラウザとサーバーの間で行われるやり取りについて知る必要があります。 互いが好き勝手にデータを送受信しても、意味のあるやり取りは成立しません。 そこで、ブラウザとサーバーの間でデータを送受信する際には、一定の手順に従う必要があります。 この手順のことをプロトコルと呼び、Web の世界では、HTTP と呼ばれるプロトコルが用いられます。
ブラウザは、アドレスバーに URL が入力されると、その情報をもとに HTTP を用いてサーバーと通信します。
例えば、先ほどの例で使用した http://localhost:3000/lang/ja
という URL は、次のように解釈されます。
- プロトコル:
http
またはhttps
のいずれかです。 いずれを指定しても使用されるプロトコルは HTTP ですが、https
を指定した場合は通信内容が暗号化されます。 この例ではhttp
を用いていますが、インターネット上に公開するウェブサイトではhttps
を用いることが推奨されます。 - ドメイン:
通信先のコンピューターを特定するための識別子です。
この例ではサーバーを自分のコンピューター上に構築しているため、自分自身を表す特殊なドメイン
localhost
を用いています。example.com
やfoo.example.net
は、実際のインターネット上で使われるドメイン名の例です。 - ポート:
通信先のコンピューター上で、どのプログラムと通信するかを特定するための整数で す。
ポートを変えることで、同じコンピューター上で複数のサーバーが通信を待ち受けることができます。
省略すると、プロトコル部分が
http
の場合は 80 番ポートが、https
の場合は 443 番ポートが用いられます。 - パス:
クライアントがサーバーに対し、何を要求するかを指定するための文字列です。
Linux のファイルシステムで用いられるパスと同様に、意味的には
/
記号によって階層化されますが、クライアントはサーバーに対してパスを文字列として送信するだけで、その内容はサーバーによって自由に解釈されます。
http://localhost:3000/lang/ja
という URL は、HTTP プロトコルを暗号化せずに用いて、localhost
というドメインの 3000 番ポートで待ち受けているサーバーに対して /lang/ja
というパスを要求することを意味します。
このように、URL に含まれる情報のうち、プロトコル、ドメイン、ポートはネットワーク上で通信を行うために用いられる情報です。 残りのパス部分をどのように扱うかが、サーバー側のプログラムにおける主な関心事になります。
Hello World サーバーの動作
main.mjs
のプログラムを参照しながら、ブラウザとサーバーの間でどのようなやり取りが行われているのかを確認しましょう。
import express from "express";
const app = express();
app.get("/", (request, response) => {
response.send(`Hello World! <a href="./lang/ja">日本語</a>`);
});
app.get("/lang/ja", (request, response) => {
response.send("こんにちは、世界!");
});
app.listen(3000);
node main.mjs
を実行したとき
- [2 行目]
const app = express();
により、Express のApplication
クラスのインスタンスが作成されます。 - [4 行目]
app.get("/", (request, response) => { ... });
で呼び出されたget
メソッドにより、/
というパスに対するリクエストを受けたときに実行される関数として、第 2 引数に指定された関数が登録されます。この時点では関数はApplication
インスタンスに登録されるのみで、実行はされません。 - [7 行目] 4 行目と同様に、
/lang/ja
というパスに対するリクエストを受けたときに実行される関数が登録されます。 - [11 行目]
app.listen(3000);
により、Express はリクエストを待ち受ける HTTP サーバーとして動作を開始します。
ブラウザの操作を行ったとき
- 利用者が、ブラウザのアドレスバーに
http://localhost:3000/
という URL を入力します。 - ブラウザは、
localhost:3000
で起動している Express のサーバーに対して、/
というパスに対する HTTP リクエストを送信します。 - Express は
/
に対する HTTP リクエストを受け取り、[4 行目] の関数を実行します。引数として、Express は次に示す 2 つのオブジェクトを生成して渡します。 - [5 行目] の
response.send(`...`);
により、Express は`Hello World! <a href="./lang/ja">日本語</a>`
という文字列をレスポンスとして送信します。 - ブラウザは、受け取ったレスポンスを HTML として解釈し、
Hello World!
という文字列と、日本語
というリンクを表示します。 - 利用者が、
日本語
というリンクをクリックします。 - ブラウザは、クリックされたリンクの
href
属性をもとに、アドレスバーの URL を更新し、ページ遷移を起こします。href
属性にプロトコルを含む URL が指定されていれば、その URL に遷移します。href
属性が相対パスの形式で指定されていれば、現在のパスを基準に Linux における相対パスと同様の方法で URL を更新します。この例では、更新前のパスが/
で、href
属性には./lang/ja
が指定されているため、更新後のパスは/lang/ja
になり、URL はhttp://localhost:3000/lang/ja
に変化します。
- 2 から 5 までの手順が、
/lang/ja
というパスに対して行われます。