😙

【node.js】cloud9で簡易webサーバーを構築してみる

2023/11/25に公開

背景

新しい会社に入社し、cloud9とnode.jsで開発をすることになりました。学習用として簡易webサーバーを構築してみようと思ったのでその構築の流れを説明します。

用語

cloud9

AWSが提供しているIDE。素早く開発環境を構築/削除でき、プレビュー機能でwebアプリの挙動をすぐに確認できます。またcode commitなどのAWSサービスとも連携がしやすです。手軽に開発環境を整えたい方にとっては選択肢の一つになるかなと思います。
ただプラグインなどで使い勝手を拡張できないので、個人的にはcloud9とvscodeを組み合わて開発したいなと思っています。いや今ならcursorになるのかな?開発はデスクトップでやる方が慣れているのでいずれ挑戦してみようと思います。

今回はnode.jsとして簡易webサーバーを開発していきますが、ありがたいことに下記AWSのcloud9解説ページにwebサーバーのサンプルコードがあったのでそれを流用していきたいと思います。
参考ページはAWS cloud9になります。

さらに豆知識ですが、cloud9のプレビューで確認する際、使用できるポート番号は8080、8081、8082のいずれかとのことです。私はポートを3000番あたりに変更してどうにかできないか試した後に上記のページに行きつきました。ポートの仕様とサンプルコードがあるなら早く教えてほしかったよ(苦笑)。

というわけで、webサーバーを実装していきましょう!

構築手順

0. 前提

cloud9
node.js 18.5.0
(環境構築はこちらの記事を参照)

1. 疎通確認

基本は上記のAWSサイトに掲載してあるサンプルコードをコピペしてファイルを作成するだけです。用意するファイルはwebサーバーの動作をするserver.jsとUIのindex.htmlです。server.jsではvarが使われていますが、公開されて長いのかもしれないですね。またserver.jsの中身を見てみると、404の実装がされています。

server.js
var http = require('http');
var fs = require('fs');
var url = require('url');

http.createServer( function (request, response) {
  var pathname = url.parse(request.url).pathname;
  console.log("Trying to find '" + pathname.substr(1) + "'...");

  fs.readFile(pathname.substr(1), function (err, data) {
    if (err) {
      response.writeHead(404, {'Content-Type': 'text/html'});
      response.write("ERROR: Cannot find '" + pathname.substr(1) + "'.");
      console.log("ERROR: Cannot find '" + pathname.substr(1) + "'.");
    } else {
      console.log("Found '" + pathname.substr(1) + "'.");
      response.writeHead(200, {'Content-Type': 'text/html'});
      response.write(data.toString());
    }
    response.end();
  });
}).listen(8080, 'localhost'); // Or 8081 or 8082 instead of 8080. Or '127.0.0.1' instead of 'localhost'.
index.html
<html>
  <head>
    <title>Hello Home Page</title>
  </head>
  <body>
    <p style="font-family:Arial;color:blue">Hello, World!</p>
  </body>
</html>

2つのファイルが準備できたらまずはターミナルで下記のコマンドを実行し、簡易webサーバーを起動します。

node server.js

続いて、上記のターミナルとは別ターミナルを起動してからcurlコマンドでhttpアクセスを試みます。-vオプションは詳細な情報(httpのリクエスト、レスポンスのヘッダ情報)を表示するためにつけています。

curl -v http://localhost:8080/index.html
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /index.html HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.81.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Type: text/html
< Date: Fri, 24 Nov 2023 19:11:09 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< Transfer-Encoding: chunked
< 
<html>
  <head>
    <title>Hello Home Page</title>
  </head>
  <body>
    <p style="font-family:Arial;color:blue">Hello, World!</p>
  </body>
* Connection #0 to host localhost left intact

cloud9を使用されている方はプレビューでindex.htmlのアクセスを確認することができます。下記の12a34567b8cd9012345ef67abcd890e1から始まる文字列はcloud9が環境に割り当てるIDで、cloud9ではプレビューを見るときのURLは下記の形式をとります。cloud9上でローカルホスト(localhostや127.0.0.0)にアクセスしてもプレビューできないのでご注意を。
詳しくはAWS cloud9 実行中のアプリケーションのプレビューをご参照ください。

# 下のURLは環境ごとに違います。
https://12a34567b8cd9012345ef67abcd890e1.vfs.cloud9.us-east-2.amazonaws.com:8080/index.html

2. ルートアクセス(/)対応

動作確認だけだと何も工夫がないので、ルートアクセスした場合の動作を追加実装してみます。server.jsにルートアクセスの判定処理を入れて見ました。その後curlコマンドでアクセスして確認すします。結果を見てみると、上から三行目(GET / HTTP/1.1)でルートにアクセスしており、無事htmlの中身が取得できていますね。

server2.js
var http = require('http');
var fs = require('fs');
var url = require('url');

http.createServer( function (request, response) {
  var pathname = url.parse(request.url).pathname;
  
  //ルートアクセスの判定
  pathname = pathname.endsWith('/') ? pathname + 'index.html' : pathname;
  
  console.log("Trying to find '" + pathname.substr(1) + "'...");

  fs.readFile(pathname.substr(1), function (err, data) {
    if (err) {
      response.writeHead(404, {'Content-Type': 'text/html'});
      response.write("ERROR: Cannot find '" + pathname.substr(1) + "'.");
      console.log("ERROR: Cannot find '" + pathname.substr(1) + "'.");
    } else {
      console.log("Found '" + pathname.substr(1) + "'.");
      response.writeHead(200, {'Content-Type': 'text/html'});
      response.write(data.toString());
    }
    response.end();
  });
}).listen(8080, 'localhost'); // Or 8081 or 8082 instead of 8080. Or '127.0.0.1' instead of 'localhost'.
curl -v http://localhost:8080/
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.81.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Type: text/html
< Date: Fri, 24 Nov 2023 19:23:31 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< Transfer-Encoding: chunked
< 
<html>
  <head>
    <title>Hello Home Page</title>
  </head>
  <body>
    <p style="font-family:Arial;color:blue">Hello, World!</p>
  </body>
* Connection #0 to host localhost left intact

所感

意外と簡単に動作確認ができました。数年前にJavaで簡単なネットワークプログラミングを勉強したことがあるのですが、そのときよりもさくっと実装できた印象です。

このプログラムをベースに簡単なAPIの実装などもできそうですね。いろいろなサンプルコードを動かしながら理解を深めていきたいと思います。

Discussion