48
53

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

接近戦に強いExpress入門 ~Webサーバー、テンプレートエンジン、セッション、BASIC認証~

Last updated at Posted at 2019-02-24

2021年10月4日更新: 最新のExpressは"body-parser"が内蔵になった件

概要

ExpressはNode.jsの定番Webフレームワークです。本稿ではExpressでやりたい あんなこと、こんなことちゃんと仕組みを理解しつつハンズオンで試します。ゼロからはじめるので、node.js環境さえあればOKです。

やりたいこと

  • 静的コンテンツを表示するWebサーバーをつくる
  • 指定されたパスにアクセスがあったら動的に応答する
  • Expressの仕組みを理解する
  • アクセスログを取得する
  • WebAPIのようにJSONを返す
  • RESTFullなAPIのようにURL内にパラメータを入れる
  • ファイルをまるごと返す
  • テンプレートエンジンを使う
  • セッションを使う
  • BASIC認証を使う

想定読者

  • node.jsnpmをつかったことがある人

対象環境

  • express 4.17.1

ソースコード

紹介する全ソースコードは以下にあります
https://github.com/riversun/express-examples

以下のようにすれば、すぐに試すことができます

git clone https://github.com/riversun/express-examples.git
npm install
npm start

準備(Expressをインストール)

  • プロジェクト用のディレクトリを作る

ゼロから使えるようにするので、まずプロジェクト用のディレクトリから作る。

mkdir webserver
cd webserver
  • npm init する

npm initをしてnpmプロジェクトを初期化する。

エンターを9回押せばOK。すると、package.jsonが自動生成される。


npm init

package name: (webserver)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to /webserver/package.json:

{
  "name": "webserver",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this ok? (yes) yes
  • Express をインストールする
npm install express

これで Expressが使えるようになった。

静的Webサーバーを作る

さっそく、静的ファイルをホスティングできるWebサーバーを作る。
ひとまずは、今作ったプロジェクトのカレントディレクトリ以下をWebとして公開する。

静的なファイルをホスティングするコードは以下のとおり。とっても簡単。

webserver.js
const express = require("express");

const app = express();
const port=8080;

app.use(express.static('./'));

app.listen(port, ()=> {
    console.log('Server started on port:'+port);
});

コードで注目するべきポイントは以下。 静的ファイルを配信する場合はこのように**app.use**で**express.static**を使う
app.use(express.static('./'));

app.useの中身に指定されているのはexpress.staticだが、これの実体は **function(req,res,next){}**の形式の関数で、この関数のなかで、req(=ブラウザからのrequest)をハンドリングして、指定されたパスに相当する静的ファイルがみつかればそれを返すという処理をしている。

express.staticのようにリクエストに応じた処理をしてくれるfunctionmiddlewareと呼ぶ。後述するが、ここでは要するにmiddlewareは、**「あるリクエストを横取りして処理してくれる関数」**と覚えておく。

package.jsonに起動コードを書く

package.jsonに起動コードを書く。

package.json
{
  "name": "webserver",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start":"node webserver.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.16.4"
  }
}

追加した部分はここ。

    "start":"node webserver.js",

index.html を書く

表示のために、index.htmlを作る。

index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>Hello express web server!</h1>
</body>
</html>

実行する

npm start
Server started on port:8080

これでwebサーバーが起動できた!

http://localhost:8080 にアクセス

image.png

無事に表示できた!

ご参考:express.static404エラーを出したいとき

ちなみに、ファイルがみつからなかったときはどうするか。
その場合の挙動を fallthroughというオプションで指定することができる。

app.use(express.static('./', {fallthrough: true}));

fallthrough=trueの場合は、ファイルがみつからない場合はexpress.staticの内部でnext()が呼ばれる。つまり、そのまま次の処理に移行するので特にエラーなどは発生しない。
fallthrough=falseの場合は、内部でnext(err)が呼ばれ、エラー扱いとなる。
デフォルトはfalthrough=true
となる。

もし、ExpressをWebサーバーとして使いたくて、かつ独自の404エラーを返したい場合は、fallthrough=trueとして、express.static処理終了後の移行先として app.useでエラー処理をするコードを書けば良い。(以前はfallthroughは「app.router で受けよう」みたいなやり方が推奨されていたが、今は使えなくなった)

指定されたパスへのアクセスに対応する

静的ファイルだけでなく、指定されたパスへのアクセスに対応するため以下のようにした。

webserver.js
const express = require('express');

const app = express();
const port = 8080;

app.use(express.static('./'));

app.get('/test', function (req, res) {
    res.send('This is a test!');
});

app.get('/*', function (req, res) {
    res.send('<html><body><h1>Others</h1></body></html>');
});

app.listen(port, () => {
    console.log('Server started on port:' + port);
});

追加した部分はこうなる。


app.get('/test', function (req, res) {
    res.send('This is a test!');
});

app.get('/*', function (req, res) {
    res.send('<html><body><h1>Others</h1></body></html>');
});

app.getは「HTTP GETリクエストをハンドリングするよ」という意味でここでは、/testというパスと**/*というパスを指定している。
上記パスにアクセスがあったときにはコールバックとして
function(req,res)が実行されるが、そのfunction内でres.sendによってテキストをレスポンスとして返す。ちなみに、res.send(テキスト)のようにテキストを返すときはContent-Typeは自動的にtext/html**となる。

ということで **http://localhost:8080/test**にGETリクエストがあれば**This is a test!を返し、それ以外のパス、たとえばhttp://localhost:8080/hoge**にアクセスがあれば**Others**を返す。

実行してみると、以下のようにうまく動いた。

http://localhost:8080/test
image.png

http://localhost:8080/hoge
image.png

HTTP GET以外のメソッドに対応させる場合

POSTapp.postPUTapp.putDELETEapp.deleteをそれぞれ使えば良い。

app.useとは何か(ついでに、Expressの動作の仕組みも学ぶ)

さて、やや静的Webサーバーの話から横道にそれるが(でも必要な知識を)あるリクエストを横取りして処理してくれるmiddlewareについて、もう少し仕組みを理解したい。

Expressは概略すると以下のような仕組みで動いている。

image.png

あるパス(例えば /)にリクエストがあると、そのパスを担当するモジュールがそのリクエストを受け付けて、何らかの処理をしてレスポンスを返す。このモジュールを**Router(ルーター)**と呼ぶ。

const app = express();

とやると、 app の中にはひそかに Router ができている。なので、まず1つRouterが準備された気になって次をみていく。

このRouterには、「Routerにやって来たリクエストを横取りして処理させる人」を追加することができ、これが前述のmiddlewareとなる。

image.png

ようやく登場するが、このrequestを横取りさせるために、middlewareを登録する方法が app.useとなる。

app.useの使い方

app.use(function (request, response, next) {
  next();
});

のようにすると、Routerに来たリクエストが、この**function(req,res,next){}**関数を通過する。

この関数の中でrequestを分析して何か処理をしたり、そのままresponseを返したりしてOK。

では、この中にある**next()**は何かというと、**next()**を実行すると次に処理を移行させることができる。

next();

というのも、middlewareは複数登録することが可能となっている。

以下のようにすると、funcA→funcBの順番でmiddlewareの関数が実行される。
(ただし各middlewareで**next()**が実行されないと処理はそこで止まる)

app.use(funcA);
app.use(funcB);
app.get('/test', function (req, res) {
    res.send('<html><body><h1>Test</h1></body></html>');
});

app.useをすると、ExpressのRouterの内部では、middlewareRouterがもつスタックに積まれる。複数回のapp.useを実行すればそれがスタックに積まれて、リクエストがあったときに順番に実行されていく。(「リクエスト処理のパイプライン」などといわれることもある)

図にするとこんなイメージ。

image.png

HTTP GETメソッドに反応する app.get(や HTTP POSTメソッドに反応する app.postなども)内部的には同じようにRouterが持つスタックにつまれる。

app.useには以下のようにあるパスを指定して、そのパスに反応するように指定することもできるが、app.useの場合はたとえば**/mypathを指定した場合/mypath/path1**のように指定したパス以下にも反応する。

app.use( "/mypath" , myfunc);

Routerを追加することも可能

さきほど、ひそかに(=暗黙的に)アプリケーション用のRouterができている旨書いたが、以下のようにapp.Router()とすることで、明示的に新しいRouterを生成できる。

const newRouter1=app.Router();
const newRouter2=app.Router();
app.use('/path1', newRouter1);
app.use('/path2', newRouter2);

image.png

このようにRoutermiddlewareの概念がつかめると、Expressはかなりシンプルなアーキテクチャであることがわかる。(横道だがJavaの軽量サーバーであるJettyのアーキテクチャもこれにかなり近い。あちらはmiddlewareのことをhandlerと読んでいる)

middlewareの詳しい使い方の例はここを参照
https://expressjs.com/en/4x/api.html#middleware-callback-function-examples

#WebAPIのようにJSONを返す

以下のようにすれば、JSONフォーマットでレスポンスされる。
Content-Typeは自動的にapplication/json; charset=utf-8となる。

(以下は、POSTで JSONテキストが送信されてくることを想定する)

app.set('json spaces', 2);
app.get('/api', function (req, res) {
    res.json({name: 'John Doe', attr: {age: 30, sex: 'male'}});
});

app.post('/api', function (req, res) {

    const posted = req.body;
    console.log('request body=' + JSON.stringify(posted));

    res.json({name: 'John Doe', attr: {age: 30, sex: 'male'}});
});

app.set('json spaces', 2);(※)によってインデント幅をスペース2個ぶんと指定しているが、これを指定することでJSONがフォーマットされる。

app.setアプリケーション設定プロパティ(application setting property)という。

これを webserver.jsに追加して http://localhost:8080/api にアクセスすると、

image.png

JSONがフォーマットもされてレスポンスされた。

ちなみに、expressでPOSTのリクエストボディを処理するには bodyparserをインストールして、ミドルウェアを有効化する必要がある

ちなみに、expressでPOSTのリクエストボディを処理するには内蔵されているbodyParserを有効化する。

express v4.16より前のバージョンではPOSTのリクエストボディを処理するために外部の body-parser というパッケージの導入が必要だったが、v4.16以降はexpressに内蔵された。(内蔵されているのは body-parser そのものではある)

以下でbodyparserを有効にする

app.use(express.urlencoded({extended: true}));// "application/x-www-form-urlencoded"なデータが送信される場合にはこれが必要
app.use(express.json()); // JSONテキストが送信される場合にはこれが必要

express.urlencodedとexpress.jsonの挙動を詳しく理解したければ body-parserのソース(urlencoded,json)を読むと良い。

すると

req.body

でリクエストボディを取得できる

URLに含まれる動的パラメータを取得する

RESTFullなAPIのように http://localhost:8080/users/3000 のようにアクセスできるようにするには以下のようにする。


app.get('/users/:userId', function (req, res) {
    res.json({name: `John Doe`, userId: `${req.params.userId}`, attr: {age: 30, sex: 'male'}});
});

/users/:userIdの**:userIdの部分が動的パラメータとなる。取得するにはreq.params.userId**のようにする。

これを webserver.jsに追加して http://localhost:8080/users/3000 にアクセスすると、

image.png

userIdの部分を抜き出すことができている。

アクセスログを取得する

共通処理として、各リクエストがあったときに、ログを取得できるようにする。
そのために前述したapp.useをつかって以下のようにmiddlewareとして実装する。


app.use(function (req, res, next) {
    const reqUrl = req.protocol + '://' + req.get('host') + req.originalUrl;
    const reqDate = new Date();
    const srcIpAddr = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
    console.log(`${reqDate} Access '${reqUrl}' from ${srcIpAddr}`);
    next();
});

最後の**next()**で次の処理に移る。

コードは以下のようにログ取得用のmiddlewareを登録するapp.useは上部に書いておく。

webserver.js
const express = require('express');

const app = express();
const port = 8080;

app.use(function (req, res, next) {
    const reqUrl = req.protocol + '://' + req.get('host') + req.originalUrl;
    const reqDate = new Date();
    const srcIpAddr = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
    console.log(`${reqDate} Access '${reqUrl}' from ${srcIpAddr}`);
    next();
});

app.use(express.static('./'));

app.get('/test', function (req, res) {
    res.send('This is a test!');
});

...省略...

app.listen(port, () => {
    console.log('Server started on port:' + port);
});

これでnpm startして実際に以下のURLアクセスしてみると、ログ用のmiddlewareが動作して、ちゃんとログがとれている。

http://localhost:8080/index.html
http://localhost:8080/users/3000

npm start
Server started on port:8080
Sat Feb 23 2019 21:03:54 GMT+0900 (東京 (標準時)) Access 'http://localhost:8080/index.html' from ::1
Sat Feb 23 2019 21:04:01 GMT+0900 (東京 (標準時)) Access 'http://localhost:8080/users/3000' from ::1

ファイルを指定してレスポンスする

res.sendFileをつかうと、ファイルを送る(レスポンス)することができる。Content-Typeはファイル名の拡張子から判定される。

app.get('/file' , function(req, res){
    res.sendFile(__dirname+'/index.html');
});

テンプレートエンジンを使う

expressはデフォルトでpugmustacheEJSといったテンプレートエンジンに対応している。
ここではpugをつかってテンプレートエンジン機能をためす。

pugをインストールする

npm install pug

package.jsonは以下のようになる

package.json
{
  "name": "webserver",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node webserver.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.16.4",
    "pug": "^2.0.3"
  }
}

** "pug": "^2.0.3"***が追加された。

次にpugのテンプレートを記述する。こんな感じで。

index.pug
html
    head
        title= mytitle
    body
        h1= mymessage

次にwebserver.jsを編集していく。

app.set('view engine', 'pug')
app.set('views', './')

app.get('/pug', function (req, res) {
    res.render('index', { mytitle: 'My Title', mymessage: 'Hi, Pug!' })
});

上記コードだが、まずexpressが使うテンプレートエンジンをアプリケーション設定プロパティで指定する。

expressで使うテンプレートエンジンの種類を指定する
app.set('view engine', 'pug')

でテンプレートエンジンとしてpugを指定する。


次に、pugのテンプレートファイルを置くディレクトリを指定する。さっきつくった、index.pugの置き場所となる。デフォルトでは**./views**だが、ここではルートディレクトリ **./**を指定する。

pugのテンプレートファイルを置くディレクトリ

app.set('views', './')

次に、テンプレートにある mytitlemymessageに値を入れる。

app.get('/pug', function (req, res) {
    res.render('index', { mytitle: 'My Title', mymessage: 'Hi, Pug!' })
});

ここでは、res.render('index', { mytitle: 'My Title', mymessage: 'Hi, Pug!' })indexという名前のテンプレートファイルの、mytitlemymessageに値を入れている。

さて、これでnpm startして http://localhost:8080/pug にアクセスすると、

image.png

うまく動作した。

こういう↓ソースが生成される

<html><head><title>My Title</title></head><body><h1>Hi, Pug!</h1></body></html>

テンプレートエンジンの動作についてより詳しくはここを参照
http://expressjs.com/en/advanced/developing-template-engines.html

セッションを使う

ここではセッションの使い方をみていく。
ブラウザで更新ボタンをおすとカウントアップしていく例をみる。

セッションとは、複数回のHttpリクエスト-レスポンスのやりとりを一連のセッションという概念で取り扱うためのもので、その実現には大昔からCookieが使われている。

expressでセッション機能を使うために、このCookieの使い方の違いで2つのアプローチがあり、Cookieはセッションの識別用にだけ使いデータはサーバーに格納する方式のexpress-sessionというモジュールと、Cookieにセッションのデータそのものを格納する方式のcookie-sessionというモジュールが利用できる。

それぞれの特徴は以下のとおり。

モジュール セッション情報の保存場所 Cookieの利用方法
express-session サーバー セッションの識別子(sessionId)だけをCookieに保存する。セッションデータはサーバーサイドのDB等に保存する。
cookie-session クライアント(ブラウザ) セッションのデータそのものをCookieに保存する。そのためサーバー側にDB等の準備は不用。

本稿ではexpress-sessionを使うのでさっそくインストール。

npm install express-session

これで、express-sessionがインストールできたので、コードを書いていく。
ブラウザを更新するとカウントアップする例となる。

webserver.js抜粋(セッションをつかってカウントアップしていく)
const session = require('express-session');
const memoryStore = new session.MemoryStore;

const sess = {
    secret: 'mysecret',
    resave: false,
    saveUninitialized: true,
    cookie: {maxAge: 1000 * 60 * 60 * 24 * 30},
    store: memoryStore
};

if (app.get('env') === 'production') {
    app.set('trust proxy', 1); // trust first proxy
    sess.cookie.secure = true; // serve secure cookies
}
app.use(session(sess));

app.get('/counter', function (req, res, next) {
    console.log(req.session.counter);
    if (req.session.counter) {
        req.session.counter++;
    } else {
        req.session.counter = 1;
    }

    res.send(`<html><body><p>${req.session.counter}</p>
              <p>expires in:${req.session.cookie.maxAge / 1000}s</p></body></html>`);
});


コードを上からみていく。

const sess = {
    secret: 'mysecret',
    resave: false,
    saveUninitialized: true,
    cookie: {maxAge: 1000 * 60 * 60 * 24 * 30},
    store: memoryStore
};

secret:sessionIdへの署名(暗号化)に必要。任意の文字列で指定する。
resave:リクエストを通してセッションが変更されなくても強制的にセッション情報をセッションストアに保存するか否か。
saveUninitialized:初期化されていないセッションを強制的にセッションストアに保存するか否か。
cookie.maxAge:cookieの有効期限。ここでは30日をセットしている。
store:cookieのストア(保存先)を指定している。デフォルトでは MemoryStore となるが明示的に指定した。本番環境では永続化のためデータベースを指定するのが一般的。ストアの種類はここを参照。


次はここ。ここでは本番環境で実行されるときのみセットされる設定を記述している。

if (app.get('env') === 'production') {
    app.set('trust proxy', 1); // trust first proxy
    sess.cookie.secure = true; // serve secure cookies
}
app.use(session(sess));

**app.set('trust proxy', 1);**は「プロキシーサーバーからn番目のホップをクライアントとして信頼するよ」という設定となる。(※)

sess.cookie.securesess={cookie:{secure:true}}を設定しているのと同等だが、secure:trueはセキュアなCookieを使うという設定だが、これは「HTTPSベースのリクエストの場合のみCookieが有効になる」という設定となる。また前述のtrust proxyの設定を同時にしておく必要がある。

trust proxyが適切に設定されていないと、例えばアクセスログを取るときにクライアント(ユーザー)がプロキシー経由でアクセスしてきたとき、誤ってプロキシーサーバーのIPアドレスをクライアントのIPアドレスとしてしまう。詳しくはここ

**app.use(session(sess));**でセッションを有効にする(=セッション用処理用のミドルウェアを登録する)


次はここで実際にカウントアップする。
セッションオブジェクトは req.session になるので、ここにデータをセットしていけばOK。

セッションをつかってカウントアップする
app.get('/counter', function (req, res, next) {
    console.log(req.session.counter);
    if (req.session.counter) {
        req.session.counter++;
    } else {
        req.session.counter = 1;
    }

    res.send(`<html><body><p>${req.session.counter}</p>
              <p>expires in:${req.session.cookie.maxAge / 1000}s</p></body></html>`);
});

これを実行して、 http://localhost:8080/counter にアクセスし、
更新ボタンをおしていくとセッションに記憶されたカウンター変数がカウントアップされていく。

dd2.gif

BASIC認証を使う

BASIC認証も比較的簡単に導入できる。BASIC認証には、basic-authというモジュールを使う。

npm install basic-auth

ここでは、あるURL以下(/admin)だけにBASIC認証をかける例をみていく。
コードは以下のようになる。

webserver.jsの抜粋
const authApp = express.Router();
app.use('/admin', authApp);

const basicAuth = require('basic-auth');

authApp.use(function (req, res, next) {
    const credentials = basicAuth(req);
    if (!credentials || (credentials.name !== 'admin' || credentials.pass !== 'mypassword')) {
        const REALM = 'secure!';
        res.header('WWW-Authenticate', 'Basic realm="' + REALM + '"').status(401).end('Access denied');
    } else {
        next();
    }
});

authApp.get('/test', function (req, res) {
    res.send('<html><body><h1>Auth Page</h1></body></html>');
});

authApp.get('/*', function (req, res) {
    res.send('<html><body><h1>Others in auth page</h1></body></html>');
});

const authApp = express.Router();
app.use('/admin', authApp);

あるURL以下だけに処理をかけたいので、Routerをつかう。**express.Router()**とすると新しいRouterを生成できる。
app.use('/admin', authApp);にて、/admin*というパス名をもったURLにアクセスがあったら、authAppというRouterを使うように設定する。/admin/testのようなURLの場合もこのRouterが使われる。


次はBASIC認証のコードとなる

const basicAuth = require('basic-auth');

authApp.use(function (req, res, next) {
    const credentials = basicAuth(req);
    if (!credentials || (credentials.name !== 'admin' || credentials.pass !== 'mypassword')) {
        const REALM = 'secure!';
        res.header('WWW-Authenticate', 'Basic realm="' + REALM + '"').status(401).end('Access denied');
    } else {
        next();
    }
});

authApp.useで、/admin*用のルーターにBASIC認証処理のmiddlewareを実装している。

const credentials = basicAuth(req);でユーザーからのリクエストに格納されているBASIC認証のCredential(ここでは、ユーザー名とパスワード)を取得することができる。
もし、Credentialが指定されていない または、 ユーザー名・パスワードの組み合わせが間違っていれば、以下のようにBASIC認証を求めるレスポンスを返す。

res.header('WWW-Authenticate', 'Basic realm="' + REALM + '"').status(401).end('Access denied');

一方、CredentialがOKなら**next()**で次の処理に移行する。


あとはBASIC認証をかけるURLと処理内容を書いていけばOK。

authApp.get('/test', function (req, res) {
    res.send('<html><body><h1>Auth Page</h1></body></html>');
});

authApp.get('/*', function (req, res) {
    res.send('<html><body><h1>Others in auth page</h1></body></html>');
});

authApp.get('/test', ...は、/admin用のRouterにセットされているのでアクセスするときには http://localhost:8080/admin/test となる。

さっそくBASIC認証のページにアクセスしてみると、以下のように、BASIC認証ダイアログが表示される。

image.png

コードで指定した adminmypasswordとそれぞれ入力すると無事ページが表示された。

image.png

コードの全体像

これまでの実装した機能を全部入りにしたコードは以下のようになります

webserver.js
const express = require('express');

const session = require('express-session');
const memoryStore = new session.MemoryStore;

const app = express();
const authApp = express.Router();

const port = 8080;

//middleware for logging
app.use(function (req, res, next) {
    const reqUrl = req.protocol + '://' + req.get('host') + req.originalUrl;
    const reqDate = new Date();
    const srcIpAddr = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
    console.log(`${reqDate} Access '${reqUrl}' from ${srcIpAddr}`);
    next();
});

//middleware for session
const sess = {
    secret: 'mysecret',
    resave: false,
    saveUninitialized: false,
    cookie: {maxAge: 1000 * 60 * 60 * 24 * 30},
    store: memoryStore
};

if (app.get('env') === 'production') {
    app.set('trust proxy', 1); // trust first proxy
    sess.cookie.secure = true; // serve secure cookies
}
app.use(session(sess));

//middleware for static pages
app.use(express.static('./'));

//router for basic authentication pages
app.use('/admin', authApp);


app.get('/test', function (req, res) {
    res.send('This is a test!');
});

//provide json api
app.set('json spaces', 2);
app.get('/api', function (req, res) {
    res.json({name: 'John Doe', attr: {age: 30, sex: 'male'}});
});

app.get('/users/:userId', function (req, res) {
    res.json({name: `John Doe`, userId: `${req.params.userId}`, attr: {age: 30, sex: 'male'}});
});

//provide file
app.get('/file', function (req, res) {
    res.sendFile(__dirname + '/index.html');
});

//provide pages generated by template engine
app.set('view engine', 'pug');
app.set('views', './');
app.get('/pug', function (req, res) {
    res.render('index', {mytitle: 'My Title', mymessage: 'Hi, Pug!'});
});

//provide session page
app.get('/counter', function (req, res, next) {
    console.log(req.session.counter);
    if (req.session.counter) {
        req.session.counter++;
    } else {
        req.session.counter = 1;
    }

    res.send(`<html><body><p>${req.session.counter}</p>
              <p>expires in:${req.session.cookie.maxAge / 1000}s</p></body></html>`);
});

app.get('/*', function (req, res) {
    res.send('<html><body><h1>Others</h1></body></html>');
});


//provide basic-auth pages
const basicAuth = require('basic-auth');
authApp.use(function (req, res, next) {
    const credentials = basicAuth(req);
    if (!credentials || (credentials.name !== 'admin' || credentials.pass !== 'mypassword')) {
        const REALM = 'secure!';
        res.header('WWW-Authenticate', 'Basic realm="' + REALM + '"').status(401).end('Access denied');
    } else {
        next();
    }
});

authApp.get('/test', function (req, res) {
    res.send('<html><body><h1>Auth Page</h1></body></html>');
});

authApp.get('/*', function (req, res) {
    res.send('<html><body><h1>Others in auth page</h1></body></html>');
});

app.listen(port, () => {
    console.log('Server started on port:' + port);
});


まとめ

  • Expressはとてもシンプルに強力な機能を実装できることがわかりました。今後も出番が多そうです。

  • 紹介した全ソースコードは以下にあります
    https://github.com/riversun/express-examples

  • 以下のようにすれば、すぐに試すことができます

git clone https://github.com/riversun/express-examples.git
npm install
npm start

サーバー起動後のお試しURL

48
53
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
48
53

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?