見守りカメラ Qwatch TS-NS110W から Node.js で画像を取得する記事で request のサンプル書いていたら、エラーハンドリングがちゃんとできてなかったので、直してみます。
以前のコード
const request = require('request'); const fs = require('fs'); const url = 'http://<IPAddress>:<httpPort>/snapshot.jpg'; const options = { 'auth': { 'user': 'username', 'pass': 'password', 'sendImmediately': false } }; request.get(url, options).pipe(fs.createWriteStream('snapshot-record.jpg'))
前回の記事 ですが、正常系しか試してなくて、仮にエラーが起きたりアカウント認証できなくても、そのエラーをそのまま画像にしてしまって、中が見れないという状況になってました。
修正したコード
といいつつも「エラーを判定しつつ、その時は pipe の前で止めてデータを受け入れない」という処理が、思いのほか、調べるのが大変でした。
紆余曲折を経て、以下の記事を発見しました。
Simplified Stream/Pipe Error Handling · Issue #647 · request/request
ほうっておくと、やっぱり pipe が走ってしまうので pause で止めて今回の request 参照を保持しつつ、レスポンスを待つところが大事なところ。
HTTP ステータスエラーやそのほかのタイムアウトのようなエラーを判定して、もしも、正常に動いたときだけ今回の request 参照 で pipe を再開して保存する動きを作るようです。思ったより複雑だった・・・。
ということで、反映したソースはこちら。
request = require('request'); const fs = require('fs'); const url = 'http://<IPAddress>:<httpPort>/snapshot.jpg'; const options = { 'auth': { 'user': 'username', 'pass': 'password', 'sendImmediately': false } }; // https://github.com/request/request/issues/647#issuecomment-499518677 let r = request.get(url, options); // 変数 r で参照を保持 r.pause(); // 一旦リクエストを止めて待つ r.on('response', function(response) { if (response.statusCode === 200) { r.pipe(fs.createWriteStream('snapshot-record.jpg')) .on('error', function(err) { // error handling here console.log('createWriteStream error handling here'); console.log('err: ' + err); }); r.resume(); } else { // status "error" handling here console.log('HTTP status "error" handling here'); // 例 : response.statusCode:401 認証エラーとか console.log('response.statusCode: ' + response.statusCode); } }) .on("error", function(err) { // error handling here // 例 : err: Error: connect ETIMEDOUT 192.168.XXX.XXX:PORT console.log('request error handling here'); console.log('err: ' + err); });
うーむ、正直、あまり実装の想像つかなかったし、連携するときにはなかなか複雑な印象。こうなると、 await / async や Promise で非同期処理を行うほうが見通しが良いなあと思いつつ、とにもかくにも対処法が分かって良かったです!