Node.js
Expressを使用したWebアプリケーション
サーチ…
前書き
Expressは、最小限で柔軟なNode.js Webアプリケーションフレームワークであり、Webアプリケーションを構築するための強力な機能を提供します。
Expressの公式ウェブサイトはexpressjs.comです。ソースはGitHubにあります 。
構文
- app.get(path [、middleware]、コールバック[、コールバック...])
- app.put(path [、middleware]、コールバック[、コールバック...])
- app.post(path [、middleware]、コールバック[、コールバック...])
- app ['delete'](パス[、ミドルウェア]、コールバック[、コールバック...])
- app.use(path [、middleware]、コールバック[、コールバック...])
- app.use(コールバック)
パラメーター
パラメータ | 詳細 |
---|---|
path | 指定されたコールバックが処理するパス部分またはURLを指定します。 |
middleware | コールバックの前に呼び出される1つ以上の関数。基本的に、複数のcallback 関数の連鎖。権限やエラー処理など、より具体的な処理に役立ちます。 |
callback | 指定されたpath への要求を処理するために使用される関数。それは次のように呼び出されるcallback(request, response, next) 、 request 、 response 、およびnext 、以下に記載されています。 |
コールバック request | コールバックが処理するために呼び出されているHTTPリクエストに関する詳細をカプセル化しているオブジェクトです。 |
response | サーバーが要求にどのように応答するかを指定するために使用されるオブジェクト。 |
next | 次の一致するルートに制御を渡すコールバック。オプションのエラーオブジェクトを受け入れます。 |
入門
最初にディレクトリを作成し、シェルにアクセスし、 npmを使用してExpressをインストールする必要がありますnpm install express --save
ファイルを作成し、 app.js
という名前を付け、次のコードを追加して新しいExpressサーバーを作成し、 app.get
メソッドを使用してそのサーバーに1つのエンドポイント( /ping
)を追加します。
const express = require('express');
const app = express();
app.get('/ping', (request, response) => {
response.send('pong');
});
app.listen(8080, 'localhost');
スクリプトを実行するには、シェルで次のコマンドを使用します。
> node app.js
アプリケーションはlocalhostポート8080で接続を受け付けますapp.listen
のhostname引数を省略すると、serverはマシンのIPアドレスとlocalhostで接続を受け入れます。ポートの値が0の場合、オペレーティングシステムは使用可能なポートを割り当てます。
スクリプトが実行されると、それをシェルでテストして、サーバーから期待される応答「pong」を受け取ることを確認できます。
> curl http://localhost:8080/ping
pong
また、Webブラウザを開いてurl http:// localhost:8080 / pingに移動して出力を表示することもできます
基本的なルーティング
まずエクスプレスアプリを作成します:
const express = require('express');
const app = express();
次に、このようなルートを定義することができます:
app.get('/someUri', function (req, res, next) {})
この構造体はすべてのHTTPメソッドに対して機能し、最初の引数としてパスが必要であり、そのパスのハンドラが要求オブジェクトと応答オブジェクトを受け取ります。したがって、基本的なHTTPメソッドの場合、これらはルートです
// GET www.domain.com/myPath
app.get('/myPath', function (req, res, next) {})
// POST www.domain.com/myPath
app.post('/myPath', function (req, res, next) {})
// PUT www.domain.com/myPath
app.put('/myPath', function (req, res, next) {})
// DELETE www.domain.com/myPath
app.delete('/myPath', function (req, res, next) {})
ここでサポートされている動詞の完全なリストを確認できます 。ルートとすべてのHTTPメソッドに対して同じ動作を定義する場合は、次のように使用できます。
app.all('/myPath', function (req, res, next) {})
または
app.use('/myPath', function (req, res, next) {})
または
app.use('*', function (req, res, next) {})
// * wildcard will route for all paths
1つのパスに対して複数のルート定義を連鎖させることができます
app.route('/myPath')
.get(function (req, res, next) {})
.post(function (req, res, next) {})
.put(function (req, res, next) {})
任意のHTTPメソッドに関数を追加することもできます。それらは最終コールバックの前に実行され、パラメータ(req、res、next)を引数として取ります。
// GET www.domain.com/myPath
app.get('/myPath', myFunction, function (req, res, next) {})
最後のコールバックを外部ファイルに保存して、1つのファイルにコードを入れすぎないようにすることができます。
// other.js
exports.doSomething = function(req, res, next) {/* do some stuff */};
そしてあなたのルートを含んでいるファイルで:
const other = require('./other.js');
app.get('/someUri', myFunction, other.doSomething);
これはコードをもっときれいにします。
リクエストからの情報の取得
リクエストしているURLから情報を取得する( req
はルートのハンドラ関数内のリクエストオブジェクトであることに注意してください)。このルート定義/settings/:user_id
とこの特定の例/settings/32135?field=name
考えてみましょう
// get the full path
req.originalUrl // => /settings/32135?field=name
// get the user_id param
req.params.user_id // => 32135
// get the query value of the field
req.query.field // => 'name'
リクエストのヘッダーを取得することもできます。
req.get('Content-Type')
// "text/plain"
他の情報を取得するのを簡単にするために、ミドルウェアを使用することができます。たとえば、リクエストのボディ情報を取得するには、ボディリクエストの本文を使用可能なフォーマットに変換するbody-parserミドルウェアを使用できます。
var app = require('express')();
var bodyParser = require('body-parser');
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
このようなリクエストを考えてみましょう
PUT /settings/32135
{
"name": "Peter"
}
あなたはこのように投稿された名前にアクセスできます
req.body.name
// "Peter"
同様の方法で、リクエストからクッキーにアクセスできます。また、 クッキーパーサーのようなミドルウェアも必要です
req.cookies.name
モジュラーエクスプレスアプリケーション
高速Webアプリケーションのモジュラルーターファクトリを作成するには:
モジュール:
// greet.js
const express = require('express');
module.exports = function(options = {}) { // Router factory
const router = express.Router();
router.get('/greet', (req, res, next) => {
res.end(options.greeting);
});
return router;
};
応用:
// app.js
const express = require('express');
const greetMiddleware = require('./greet.js');
express()
.use('/api/v1/', greetMiddleware({ greeting:'Hello world' }))
.listen(8080);
これにより、アプリケーションをモジュール化し、カスタマイズし、コードを再利用できるようにします。
http://<hostname>:8080/api/v1/greet
アクセスすると、出力はHello world
なりHello world
より複雑な例
ミドルウェアの工場の利点を示すサービスの例
モジュール:
// greet.js
const express = require('express');
module.exports = function(options = {}) { // Router factory
const router = express.Router();
// Get controller
const {service} = options;
router.get('/greet', (req, res, next) => {
res.end(
service.createGreeting(req.query.name || 'Stranger')
);
});
return router;
};
応用:
// app.js
const express = require('express');
const greetMiddleware = require('./greet.js');
class GreetingService {
constructor(greeting = 'Hello') {
this.greeting = greeting;
}
createGreeting(name) {
return `${this.greeting}, ${name}!`;
}
}
express()
.use('/api/v1/service1', greetMiddleware({
service: new GreetingService('Hello'),
}))
.use('/api/v1/service2', greetMiddleware({
service: new GreetingService('Hi'),
}))
.listen(8080);
アクセスする際http://<hostname>:8080/api/v1/service1/greet?name=World
出力がされますHello, World
とアクセスしhttp://<hostname>:8080/api/v1/service2/greet?name=World
は出力がHi, World
ます。
テンプレートエンジンの使用
テンプレートエンジンの使用
次のコードはJadeをテンプレートエンジンとして設定します。 (注:2015年12月現在、Jadeの名前はpug
変更されています)。
const express = require('express'); //Imports the express module
const app = express(); //Creates an instance of the express module
const PORT = 3000; //Randomly chosen port
app.set('view engine','jade'); //Sets jade as the View Engine / Template Engine
app.set('views','src/views'); //Sets the directory where all the views (.jade files) are stored.
//Creates a Root Route
app.get('/',function(req, res){
res.render('index'); //renders the index.jade file into html and returns as a response. The render function optionally takes the data to pass to the view.
});
//Starts the Express server with a callback
app.listen(PORT, function(err) {
if (!err) {
console.log('Server is running at port', PORT);
} else {
console.log(JSON.stringify(err));
}
});
同様に、 Handlebars
( hbs
)やejs
などの他のテンプレートエンジンも使用できます。 Template Engineもnpm install
てください。ハンドルバーはhbs
パッケージ、 jade
用にはjade
パッケージ、 ejs
用にはejs
パッケージがあります。
EJSテンプレートの例
EJS(他のExpressテンプレートと同様)では、サーバーコードを実行し、HTMLからサーバー変数にアクセスできます。
EJSでは、開始タグとして " <%
"、終了タグとして " %>
"を使用して終了しました。レンダリングパラメータとして渡される変数は、 <%=var_name%>
たとえば、サーバーコードに電源装置アレイがある場合
それを使用してループすることができます
<h1><%= title %></h1>
<ul>
<% for(var i=0; i<supplies.length; i++) { %>
<li>
<a href='supplies/<%= supplies[i] %>'>
<%= supplies[i] %>
</a>
</li>
<% } %>
この例では、サーバー側のコードとHTMLを切り替えるたびに、現在のEJSタグを閉じて後で新しいタグを開く必要があるため、ここではfor
コマンド内にli
を作成してEJSタグを閉じる必要がありましたfor
の最後に中かっこの新しいタグを作成する
もう一つの例
入力側のデフォルトのバージョンをサーバー側からの変数にする場合は、 <%=
例えば:
Message:<br>
<input type="text" value="<%= message %>" name="message" required>
ここでは、サーバー側から渡されるメッセージ変数が入力のデフォルト値になります。サーバー側からメッセージ変数を渡さなかった場合、EJSは例外をスローします。 res.render('index', {message: message});
を使用してパラメータを渡すことができますres.render('index', {message: message});
(index.ejsというejsファイルの場合)。
EJSタグでは、 if
、 while
または他のjavascriptコマンドを使用することもできます。
ExpressJSを使用したJSON API
var express = require('express');
var cors = require('cors'); // Use cors module for enable Cross-origin resource sharing
var app = express();
app.use(cors()); // for all routes
var port = process.env.PORT || 8080;
app.get('/', function(req, res) {
var info = {
'string_value': 'StackOverflow',
'number_value': 8476
}
res.json(info);
// or
/* res.send(JSON.stringify({
string_value: 'StackOverflow',
number_value: 8476
})) */
//you can add a status code to the json response
/* res.status(200).json(info) */
})
app.listen(port, function() {
console.log('Node.js listening on port ' + port)
})
http://localhost:8080/
outputオブジェクトの場合
{
string_value: "StackOverflow",
number_value: 8476
}
静的ファイルの提供
Expressを使用してWebサーバーを構築する場合、動的コンテンツと静的ファイルを組み合わせて提供する必要があります。
たとえば、ファイルシステムに保存されている静的ファイルであるindex.htmlとscript.jsがあるとします。
静的ファイルを持つために 'public'という名前のフォルダを使用するのが一般的です。この場合、フォルダ構造は次のようになります。
project root
├── server.js
├── package.json
└── public
├── index.html
└── script.js
これは、静的ファイルを提供するようにExpressを構成する方法です。
const express = require('express');
const app = express();
app.use(express.static('public'));
注:フォルダが設定されると、index.html、script.js、および "public"フォルダ内のすべてのファイルがルートパスで利用可能になります(urlには/public/
を指定しないでください)。これは、エクスプレスが構成された静的フォルダに関連するファイルを検索するためです。 仮想パスプレフィックスは 、以下のように指定できます。
app.use('/static', express.static('public'));
リソースを/static/
prefixの下で利用できるようにします。
複数のフォルダ
同時に複数のフォルダを定義することは可能です:
app.use(express.static('public'));
app.use(express.static('images'));
app.use(express.static('files'));
リソースを提供するとき、Expressは定義順にフォルダーを検査します。同じ名前のファイルの場合は、最初に一致するフォルダのファイルが提供されます。
Django-styleの名前付きルート
大きな問題の1つは、貴重な名前付きルートが、Expressのすぐ外でサポートされていないことです。解決方法は、サポートされているサードパーティ製のパッケージをインストールすることです(たとえば、 express-reverse :
npm install express-reverse
あなたのプロジェクトにプラグインしてください:
var app = require('express')();
require('express-reverse')(app);
次に、次のように使用します。
app.get('test', '/hello', function(req, res) {
res.end('hello');
});
このアプローチの欠点は、 高度なルータの使用法に示すように、 route
Expressモジュールを使用できないことです。この問題を回避するには、ルータのファクトリにパラメータとしてapp
を渡す:
require('./middlewares/routing')(app);
それを次のように使用します。
module.exports = (app) => {
app.get('test', '/hello', function(req, res) {
res.end('hello');
});
};
これからは、関数を定義して指定されたカスタム名前空間とマージし、適切なコントローラを指す方法を理解することができます。
エラー処理
基本的なエラー処理
デフォルトでは、Expressはレンダリングする/views
ディレクトリ内の「エラー」ビューを探します。 「エラー」ビューを作成して、エラーを処理するためにビューディレクトリに配置するだけです。エラーには、エラーメッセージ、ステータス、およびスタックトレースが書き込まれます。たとえば、次のようになります。
views / error.pug
html
body
h1= message
h2= error.status
p= error.stack
高度なエラー処理
ミドルウェア関数スタックの最後に、エラー処理ミドルウェア関数を定義します。これらには、3つの引数(err, req, res, next)
代わりに4つの引数があります。
app.js
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
//pass error to the next matching route.
next(err);
});
// handle error, print stacktrace
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
通常のミドルウェア機能と同じように、いくつかのエラー処理ミドルウェア機能を定義することができます。
ミドルウェアと次のコールバックの使用
Expressは、複数のハンドラ間で単一ルートのロジックを切断するために使用できるすべてのルート・ハンドラおよびミドルウェア機能にnext
コールバックを渡します。引き数なしでnext()
を呼び出すと、次の一致するミドルウェアまたはルートハンドラに続行するようにexpressに指示します。エラーでnext(err)
を呼び出すと、エラーハンドラミドルウェアがトリガされます。 next('route')
を呼び出すと、現在のルート上の後続のミドルウェアをバイパスし、次の一致するルートにジャンプします。これにより、ドメインロジックを自己完結型でテストが簡単で、保守や変更が容易な再利用可能なコンポーネントに分離することができます。
複数の一致するルート
/api/foo
または/api/bar
へのリクエストは、初期ハンドラを実行してメンバを検索し、各ルートの実際のハンドラに制御を渡します。
app.get('/api', function(req, res, next) {
// Both /api/foo and /api/bar will run this
lookupMember(function(err, member) {
if (err) return next(err);
req.member = member;
next();
});
});
app.get('/api/foo', function(req, res, next) {
// Only /api/foo will run this
doSomethingWithMember(req.member);
});
app.get('/api/bar', function(req, res, next) {
// Only /api/bar will run this
doSomethingDifferentWithMember(req.member);
});
エラーハンドラ
エラーハンドラは、署名function(err, req, res, next)
持つミドルウェアです。 app.get('/foo', function(err, req, res, next)
)などのルートごとに設定できますが、通常はエラーページをレンダリングする単一のエラーハンドラで十分です。
app.get('/foo', function(req, res, next) {
doSomethingAsync(function(err, data) {
if (err) return next(err);
renderPage(data);
});
});
// In the case that doSomethingAsync return an error, this special
// error handler middleware will be called with the error as the
// first parameter.
app.use(function(err, req, res, next) {
renderErrorPage(err);
});
ミドルウェア
上記の各機能は、実際には要求が定義されたルートと一致するたびに実行されるミドルウェア機能ですが、1つのルートに任意の数のミドルウェア機能を定義できます。これにより、ミドルウェアを別々のファイルで定義し、共通ロジックを複数のルートにわたって再利用することができます。
app.get('/bananas', function(req, res, next) {
getMember(function(err, member) {
if (err) return next(err);
// If there's no member, don't try to look
// up data. Just go render the page now.
if (!member) return next('route');
// Otherwise, call the next middleware and fetch
// the member's data.
req.member = member;
next();
});
}, function(req, res, next) {
getMemberData(req.member, function(err, data) {
if (err) return next(err);
// If this member has no data, don't bother
// parsing it. Just go render the page now.
if (!data) return next('route');
// Otherwise, call the next middleware and parse
// the member's data. THEN render the page.
req.member.data = data;
next();
});
}, function(req, res, next) {
req.member.parsedData = parseMemberData(req.member.data);
next();
});
app.get('/bananas', function(req, res, next) {
renderBananas(req.member);
});
この例では、各ミドルウェア機能は、それ自身のファイルまたはファイルの他の場所の変数のいずれかになり、他のルートで再利用できるようになります。
エラー処理
基本的なドキュメントはここにあります
app.get('/path/:id(\\d+)', function (req, res, next) { // please note: "next" is passed
if (req.params.id == 0) // validate param
return next(new Error('Id is 0')); // go to first Error handler, see below
// Catch error on sync operation
var data;
try {
data = JSON.parse('/file.json');
} catch (err) {
return next(err);
}
// If some critical error then stop application
if (!data)
throw new Error('Smth wrong');
// If you need send extra info to Error handler
// then send custom error (see Appendix B)
if (smth)
next(new MyError('smth wrong', arg1, arg2))
// Finish request by res.render or res.end
res.status(200).end('OK');
});
// Be sure: order of app.use have matter
// Error handler
app.use(function(err, req, res, next)) {
if (smth-check, e.g. req.url != 'POST')
return next(err); // go-to Error handler 2.
console.log(req.url, err.message);
if (req.xhr) // if req via ajax then send json else render error-page
res.json(err);
else
res.render('error.html', {error: err.message});
});
// Error handler 2
app.use(function(err, req, res, next)) {
// do smth here e.g. check that error is MyError
if (err instanceof MyError) {
console.log(err.message, err.arg1, err.arg2);
}
...
res.end();
});
付録A
// "In Express, 404 responses are not the result of an error,
// so the error-handler middleware will not capture them."
// You can change it.
app.use(function(req, res, next) {
next(new Error(404));
});
付録B
// How to define custom error
var util = require('util');
...
function MyError(message, arg1, arg2) {
this.message = message;
this.arg1 = arg1;
this.arg2 = arg2;
Error.captureStackTrace(this, MyError);
}
util.inherits(MyError, Error);
MyError.prototype.name = 'MyError';
フック:任意のreqの前と任意のresの後にコードを実行する方法
app.use()
とミドルウェアは "before"に使用でき、 closeイベントとfinishイベントの組み合わせは "after"に使用できます。
app.use(function (req, res, next) {
function afterResponse() {
res.removeListener('finish', afterResponse);
res.removeListener('close', afterResponse);
// actions after response
}
res.on('finish', afterResponse);
res.on('close', afterResponse);
// action before request
// eventually calling `next()`
next();
});
...
app.use(app.router);
この例は、デフォルトで応答後にログに追加されるロガーミドルウェアです。
この "ミドルウェア"は、注文が問題になるようにapp.router
前に使用されていることを確認してください。
オリジナル投稿はこちら
POSTリクエストの処理
app.getメソッドを使用してExpressでリクエストを処理するのと同じように、app.postメソッドを使用してポストリクエストを処理できます。
しかし、POSTリクエストを処理する前に、 body-parser
ミドルウェアを使用する必要があります。単にPOST
、 PUT
、 DELETE
などの要求の本体を解析します。
Body-Parser
ミドルウェアはリクエストの本文を解析し、 req.body
利用可能なオブジェクトに変換します
var bodyParser = require('body-parser');
const express = require('express');
const app = express();
// Parses the body for POST, PUT, DELETE, etc.
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/post-data-here', function(req, res, next){
console.log(req.body); // req.body contains the parsed body of the request.
});
app.listen(8080, 'localhost');
Cookieパーサーでクッキーを設定する
以下は、 cookie-parserモジュールを使用してCookieを設定および読み込む例です。
var express = require('express');
var cookieParser = require('cookie-parser'); // module for parsing cookies
var app = express();
app.use(cookieParser());
app.get('/setcookie', function(req, res){
// setting cookies
res.cookie('username', 'john doe', { maxAge: 900000, httpOnly: true });
return res.send('Cookie has been set');
});
app.get('/getcookie', function(req, res) {
var username = req.cookies['username'];
if (username) {
return res.send(username);
}
return res.send('No cookie found');
});
app.listen(3000);
Expressのカスタムミドルウェア
Expressでは、リクエストのチェックや応答のヘッダーの設定に使用できるミドルウェアを定義できます。
app.use(function(req, res, next){ }); // signature
例
次のコードは、 user
をリクエストオブジェクトに追加し、次の一致するルートにコントロールを渡します。
var express = require('express');
var app = express();
//each request will pass through it
app.use(function(req, res, next){
req.user = 'testuser';
next(); // it will pass the control to next matching route
});
app.get('/', function(req, res){
var user = req.user;
console.log(user); // testuser
return res.send(user);
});
app.listen(3000);
Expressでのエラー処理
Expressでは、アプリケーションで発生したエラーを処理する統合エラーハンドラを定義できます。すべてのルートとロジックコードの最後にハンドラを定義します。
例
var express = require('express');
var app = express();
//GET /names/john
app.get('/names/:name', function(req, res, next){
if (req.params.name == 'john'){
return res.send('Valid Name');
} else{
next(new Error('Not valid name')); //pass to error handler
}
});
//error handler
app.use(function(err, req, res, next){
console.log(err.stack); // e.g., Not valid name
return res.status(500).send('Internal Server Occured');
});
app.listen(3000);
ミドルウェアの追加
ミドルウェア機能は、アプリケーションの要求応答サイクルで要求オブジェクト(req)、応答オブジェクト(res)、および次のミドルウェア機能にアクセスできる機能です。
ミドルウェアの機能は、任意のコードを実行し、 res
およびreq
オブジェクトを変更し、応答サイクルを終了し、次のミドルウェアを呼び出すことができます。
非常に一般的なミドルウェアの例はcors
モジュールです。 CORSサポートを追加するには、単にインストールして、それを必要とし、次の行を追加します。
app.use(cors());
ルータまたはルーティング機能の前に
こんにちは世界
ここでは、Expressを使用して基本的なhello worldサーバーを作成します。ルート:
- '/'
- '/ wiki'
そして、残りは "404"、つまりページが見つかりません。
'use strict';
const port = process.env.PORT || 3000;
var app = require('express')();
app.listen(port);
app.get('/',(req,res)=>res.send('HelloWorld!'));
app.get('/wiki',(req,res)=>res.send('This is wiki page.'));
app.use((req,res)=>res.send('404-PageNotFound'));
注:エクスプレスは順番に経路を積み重ね、それぞれの要求に対して順番に処理するため、最終ルートとして404ルートを配置しています。