[NodeJS] nodeで例外処理を書いて、最低限落ちないサーバー実装を行うException Handler
こんにちは、@yoheiMuneです。
最近、node.jsを使ってサーバー運用を始めてみました。
初めてのことが多くて大変ですが、その分学んだこともたくさんあるので、ブログにドシドシとアウトプットしたいと思います。

例えば、以下のようなサーバーコードがあったとして、エラー部分が実行されるとサーバーは応答しなくなります。
通常「関数の未定義」みたいな初歩的なエラーはテストで発見できます。 しかし「予期せぬ入力値」などはテストケースから漏れることもあり、またエラーケースに対する実装が十分でないこともあるので、 運用中にも予期せぬエラーが発生することはぜひ想定すべきです。
Apacheなどのサーバーを利用していたり、フレームワーク(strutsやSpringとか)を使っている場合には、 こーゆうエラーもいい感じに処理してくれるのですが、node.jsでサーバーを実装するともちろんしてくれないので、大変ですねー。
エラーが発生するかもという箇所は、ちゃんとエラーハンドリングを個別に書くのがベストです。
最後までご覧頂きましてありがとうございました。
最近、node.jsを使ってサーバー運用を始めてみました。
初めてのことが多くて大変ですが、その分学んだこともたくさんあるので、ブログにドシドシとアウトプットしたいと思います。

node.jsでは1つのエラーでサーバーダウン。。
今まで最終的なエラーハンドリングは、ApacheやらSpringやらstrutsやらに任せてきた自分としては、node.jsは斬新です。 1つのJSエラーが発生するとサーバーが停止してしまいます。例えば、以下のようなサーバーコードがあったとして、エラー部分が実行されるとサーバーは応答しなくなります。
// 必要なモジュールを読み込みます。
var http = require("http");
var fs = require("fs");
var server = http.createServer(function (req, res) {
res.writeHead(200, {"Content-Type":"text/html"});
var output = fs.readFileSync("./index.html", "utf-8");
res.end(output);
});
server.listen(8080);
undefinedFunction(); // 定義していない関数の呼び出しでエラー!!!
上記の場合、例えば以下のようなエラーが表示されて、サーバーは停止します。
$ node app.js
/Users/munesadayohei/tmp/app.js:13
undefinedFunction(); // 定義していない関数の呼び出しでエラー!!!
^
ReferenceError: undefinedFunction is not defined
at Object.<anonymous> (/Users/munesadayohei/tmp/app.js:13:1)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:901:3
また、以下のように、「/」にアクセスした時に実行されるメソッドに不備があり、サーバーが停止することもあります。
// 必要なモジュールを読み込みます。
var http = require("http");
var fs = require("fs");
var server = http.createServer(function (req, res) {
res.writeHead(200, {"Content-Type":"text/html"});
var output = fs.readFileSync("./index.html", "utf-8");
// JSONパースができずエラー
var json = JSON.parse('<tag>NOT JSON FORMART</tag>');
res.end(output);
});
server.listen(8080);
「/」にアクセスすると、以下のようなエラーが発生して、サーバーは停止します。
$ node app.js
undefined:1
<tag>NOT JSON FORMART</tag>
^
SyntaxError: Unexpected token <
at Object.parse (native)
at Server.<anonymous> (/Users/munesadayohei/tmp/app.js:10:18)
at Server.EventEmitter.emit (events.js:98:17)
at HTTPParser.parser.onIncoming (http.js:2027:12)
at HTTPParser.parserOnHeadersComplete [as onHeadersComplete] (http.js:119:23)
at Socket.socket.ondata (http.js:1917:22)
at TCP.onread (net.js:510:27)
と、こんな感じでnode.jsを利用すると、1つのエラーがサーバーが停止してしまうので、なかなかスリリングです。通常「関数の未定義」みたいな初歩的なエラーはテストで発見できます。 しかし「予期せぬ入力値」などはテストケースから漏れることもあり、またエラーケースに対する実装が十分でないこともあるので、 運用中にも予期せぬエラーが発生することはぜひ想定すべきです。
Apacheなどのサーバーを利用していたり、フレームワーク(strutsやSpringとか)を使っている場合には、 こーゆうエラーもいい感じに処理してくれるのですが、node.jsでサーバーを実装するともちろんしてくれないので、大変ですねー。
node.jsでとりあえず落ちないサーバーを作る
とりあえず落ちないようにするために、Exception Handlerを実装します。 node.jsのネイティブでサポートしている仕組みで、サーバー実装の最初の方に以下ように記載します。
// 必要なモジュールを読み込みます。
var http = require("http");
var fs = require("fs");
// ★★ここがポイントです★★
// サーバー実装の前に、エラーハンドリングを記載します。
process.on('uncaughtException', function(err) {
console.log(err);
});
var server = http.createServer(function (req, res) {
res.writeHead(200, {"Content-Type":"text/html"});
var output = fs.readFileSync("./index.html", "utf-8");
// 以下のエラーが発生しても、とりあえずサーバーは生き残ります。
// JSONパースができずエラー
// var json = JSON.parse('<tag>NOT JSON FORMART</tag>');
res.end(output);
});
server.listen(8080);
// ここのエラーでも生き残ります。
// undefinedFunction();
上記のようにuncaughtExceptionイベントを実装することで、エラーが発生してもそのメソッド内で対応して、サーバーが落ちないようにできます。
ただ、uncaughtExceptionでキャッチした場合には、どのリクエストのものかは分からないので、エラーレスポンスを返すことはできません。エラーが発生するかもという箇所は、ちゃんとエラーハンドリングを個別に書くのがベストです。
// ちゃんとエラー処理を書く
try {
var json = JSON.parse('<tag>NOT JSON FORMART</tag>');
} catch (e) {
res.writeHead(400, {"Content-Type":"text/html"});
res.end('invalid format');
return;
}
最後に
node.jsを使って初めて本格的なサーバー運用を行ってますが、こんな基本的なことからいっぱい学ぶ今日この頃です。 node.jsはまだまだ楽しみなところが多くていいですね。今後もノウハウをブログに書きたいと思います。最後までご覧頂きましてありがとうございました。





