はじめに
やりたかったのは、ブラウザからPOSTされたデータをAJAXで受取DBに登録すること。
登録自体は、なんとかなったがエラー処理に苦労したので情報を残しておこうと思う。
わかっている人から見れば、わかってないなと思われそうなプログラムを組んでいると思うが、そこは恥を忍びたい。。。
プログラム構成
ソースコードは以下の通りだが、説明するとブラウザからの通信をindex.jsで受信し、DBに登録するクラスのインスタンスを生成し、登録を行う。DBに登録するクラスは、派生クラスであり、dbcontroler.jsを継承している。
try {
var controler = new tablename_control();
controler.insertNewNumber(req.body)
res.json({msg: 'sucess'})
} catch(error) {
res.status(500).send(error);
}
当初は、tablename_controlクラスのメソッド内でエラー発生時にthrow new Error()で対処できると思ったが、結論はダメだった。これが問題点1。
module.exports = class tablename_control extends Dbcontroler {
constructor () {
super();
}
async insertNewNumber(data) {
try {
data = JSON.parse(JSON.stringify(data));
var sqls = ['SQL生成処理'];
await this.insertRecode(sqls);
} catch(error) {
this.logger.error(error);
throw new Error('SeverError');
}
}
}
ここでは、JSONデータからSQLを生成して継承元のSQL実行メソッドを実行している。
module.exports = class dbcontroler extends Logger {
//省略
async insertRecode(sqls) {
try {
await this.client.connect();
for (const sql in sqls) {
await this.client.query(sqls[sql],(err,result) => {
if(err) {
throw err;
}
);
}
} catch(error) {
throw error;
} finally {
this.client.on('drain', this.client.end.bind(this.client));
}
}
}
そして、最後のソースは上記の通り。これがではQueryでエラーが発生した場合、サーバが落ちてしまう。
これが問題点2。
Queryで発生したExceptioinはcallback関数内に渡されるがそこでThrowしても、どこでもcatchしてくれなかった。これが非同期処理の大変なところではないだろうか。
修正結果
色々紆余曲折した結果下記のように修正。
module.exports = class dbcontroler extends Logger {
//省略
async insertRecode(sqls) {
try {
await this.client.connect();
for (const sql in sqls) {
await this.client.query(sqls[sql]);
}
} catch(error) {
throw error;
this.client.on('drain', this.client.end.bind(this.client));
}
}
}
Queryにcallbackを指定しないことで、Queryで発生したExceptionをキャッチ出来た。
これで問題点2はクリアできた。
だが、tablename_control.jsでのthrow new Error()をindex.jsがキャッチしてくれない問題1が発覚した。
この原因は(おそらく)、index.js内でDB登録処理が終わる前にブラウザにレスポンスを終えてしまったことにあると思う。ほんとにわたしは非同期処理に慣れていないのがわかった。
以下のように修正。
var controler = new winnum_control();
controler.insertNewNumber(req.body)
.then( () => {
res.json({msg: 'sucess'})
})
.catch((error) => {
res.status(500).send(error);
return;
});
DBの登録処理を待つように変更。
これで、DB登録エラー時にHTTPステータスコードを500に設定することができた。
ちなみにerrorをsendしているが、これは正しくブラウザ側で受信出来ていない。原因はわかないので放置している。
最後に
色々調べた結果、このような形になったがこれが正解なのか、スタンダードなのかわからない。
わたしは、try{}catch(){}の書き方になじみがあるので、このソースに違和感はあまり感じないがもっといい方法があるかもしれない。
今後そんな方法に出会ったらまた、投稿しようと思うかもしれないが、今のところはこの方法でいこうと思う。
また、私のようなはまり方をする方は少ないかもしれないが、もしそんな方がいてこの投稿が参考になってくれたら幸いです。