2022-10-04


Node/javascriptは処理が非同期で行われるので、普通にやると結果を待たずに次の処理が実行されてしまう。
<やりたいこと>
・標準httpsモジュールで外部コンテンツを取得、「取得が終わってから」次の処理へ行きたい。
・タイムアウト値を設定してタイムアウトしたらhttps通信を中止したい。
・ステータスHTTP 200番台以外はエラーとしたい。
<解決方法>
・同期したい(待ちたい)処理をまるまるPromiseクラスで囲ってしまえばよい。
・必要なデータの取得が済んだらPromise内でresolve関数に渡せば呼んだ側の戻り値としてデータが返る。
・エラーが発生した場合Errorオブジェクトを生成してreject関数に渡せば呼んだ側のcatchブロックのerrとしてエラーが返る。
・そのようにしてPromiseから返ったデータの型によって処理を分けたい場合res.constructor.nameを見ればクラスがわかるので分岐可能。
・optionsにtimeoutをミリ秒で指定可能。タイムアウトイベントが発生するのでそのときabortを呼べばよい。
<ソースコード>
JavaScript | promise_https.js | GitHub Source |
// 同期的にhttps通信するサンプル const https = require('https'); function promiseRequest(url, options, postData) { return new Promise(function (resolve, reject) { var req = https.request(url, options, (res) => { console.log('statusCode:', res.statusCode); console.log('headers:', res.headers); //200台以外はエラーとする場合 if(res.statusCode >= 300) { reject(new Error('res.statusCode >= 300')); } var chunks = []; //チャンクレスポンスストック配列 res.on('data', chunk => chunks.push(Buffer.from(chunk))) .on('end', () => { //チャンクレスポンスストリーム終了 var buffer = Buffer.concat(chunks); resolve(buffer); }); }); req.on('error', (err) => { reject(err); }); req.on('timeout', () => { req.abort(); reject(new Error('request timed out')); }); if(postData != null) { req.write(postData); } req.end(); }); } async function main() { const url = 'https://www.yahoo.co.jp/'; var options = { method: 'GET', timeout: 5000, //headers: { //'Content-Type': 'application/json', //}, }; //var postData = JSON.stringify({ // 'limit' : 50 //}); var postData = null; try { const res = await promiseRequest(url, options, postData); //Promiseがresolveするとresがここに返る console.log(res.constructor.name); // =Buffer console.log(res.toString()); } catch(err) { //Promiseがrejectするとerrがここに返る console.log(err.constructor.name); // =Error console.log(err.stack); } } main();
・async宣言した関数内でawait promiseRequestとし、https通信完了まで待つ。try~catchで囲わないと正常に動作しないので注意。
・HTTP 200番台以外をエラーとし、自分でErrorオブジェクトを生成しrejectで抜けている。
・HTTPS通信のデータ取得はチャンク(chunk)という細切れで数回に分けてストリーム取得されるため、chunks配列に都度格納し、endイベント発生時に一括Buffer変換し、処理成功としてresolveで呼び出し元へデータを返す。
・通常HTMLなどのテキストデータなら、受け取った側はtoStringで文字列変換して表示できる。
・optionsをPOSTにしてContent-Typeをjson、postData JSONデータをセットすれば、POSTメソッドによるREST APIの呼び出しにも対応する。
・optionsにtimeout5000=5秒でreq.on(timetout)が呼ばれる。その時忘れずabortして処理を中止し自前でErrorオブジェクトを生成しrejectで抜ければOK。
<実行結果>
node promise_https.js statusCode: 200 headers: { server: 'ATS', date: 'Sat, 17 Sep 2022 01:53:50 GMT', 'content-type': 'text/html; charset=UTF-8', 'accept-ranges': 'none', 'cache-control': 'private, no-cache, no-store, must-revalidate', expires: '-1', pragma: 'no-cache', 'set-cookie': [ 'B=1medvfthiaa5e&b=3&s=th; expires=Tue, 17-Sep-2024 01:53:50 GMT; path=/; domain=.yahoo.co.jp', 'XB=1medvfthiaa5e&b=3&s=th; expires=Tue, 17-Sep-2024 01:53:50 GMT; path=/; domain=.yahoo.co.jp; secure; samesite=none' ], vary: 'Accept-Encoding', 'x-content-type-options': 'nosniff', 'x-frame-options': 'SAMEORIGIN', 'x-vcap-request-id': '07baffbf-08d0-4fa1-593d-38c6fbd75061', 'x-xss-protection': '1; mode=block', age: '0', 'transfer-encoding': 'chunked', connection: 'close' } Buffer <!DOCTYPE html><html lang="ja"><head><meta charSet="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/><title>Yahoo! JAPAN</title><meta name="description" content="あなたの毎日をアップデートする情報ポータル。検索、ニュース、天気、スポーツ、メール、ショッピング、オークションなど便利なサービスを展開しています。"/> ....中略.... })();</script></body></html>
<テストでtimeout: 1としてタイムアウトを発生させた場合>
node promise_https.js Error Error: request timed out at ClientRequest.<anonymous> (/home/hogeuser/promise_https.js:31:10) at ClientRequest.emit (node:events:394:28) at TLSSocket.emitRequestTimeout (node:_http_client:761:9) at Object.onceWrapper (node:events:513:28) at TLSSocket.emit (node:events:406:35) at TLSSocket.Socket._onTimeout (node:net:486:8) at listOnTimeout (node:internal/timers:557:17) at processTimers (node:internal/timers:500:7)

※本記事内容の無断転載を禁じます。

天然素材のみを使用した、猫にやさしい猫砂【poocat-プーキャット-】

冷えに悩む女性のために【アルポカ温泉郷〜椿の湯〜】

おちゃのこさいさいは、文字どおりに、おちゃのこさいさい的に ホームページを作製できます。 カレンダー・クーポン・商品紹介・スタッフ紹介など基本的な機能を 盛りだくさん用意しています。 無料試用期間もあります、是非お試しを!

お試しワンコイン!マカ×シトルリン×クラチャイダムの活力サプリ【マカエンペラー】

オーガニックグリーン認証 ビーガンハラル対応ヘアケア『イマジェア』

糖質88%OFF&糖類ゼロで食べられるダイエット【低糖質ふすま粉パン】

頭皮のニオイにお悩みのあなたに朗報です。【クリアハーブミスト】

コラーゲンと難消化デキストリンを配合した美容にも体にもうれしい酵素が生きている本物の青汁

全国対応!アムウェイ製品買取専門店 まずは「匿名無料査定」24時間365日受付 【アムウェイ製品買取ドットコム】

【OpenAI Python API】Models/List modelsのサンプル
【Python】配列の要素を順番に取得する
PortForwarderでno hostkey algと言われ接続できない場合
【Linux】iconv/libiconvをソースコードからインストール
【OpenAI Node.js API】Images/Create image variationのサンプル
【OpenAI Node.js API】Models/Retrieve modelのサンプル
【JavaScript/Node.js】配列の要素を順番に取得する
【OpenAI Node.js API】Models/List modelsのサンプル
Node.jsでJSON返却値を[Object]ではなくフル階層で表示する
【Windows10】リモートデスクトップ間のコピー&ペーストができなくなった場合の対処法
Googleスプレッドシートを編集したら自動で更新日時を入れる
Windows版Google Driveが使用中と言われアンインストールできない場合
Googleファミリーリンクで子供の端末の現在地がエラーで取得できない場合
Googleスプレッドシートで図形をコピーして使いまわすには
【Javascript】JSON配列内にある特定要素の取得法【Node.js】
Androidホームで左にスワイプすると出てくるニュース共を一切表示させない方法
【Linux共通】プロキシサーバーの利用設定
Ubuntuで固定IPアドレスを使う設定をする