Google App Script の UrlFetchApp の 例外ハンドリングについて


UrlFetchApp を使って、Http 通信を行うスクリプトを作っていたのですが、
Http Response 200 以外のコード が返る場合は、
例外がスローされており、どうハンドリングするべきか調べた結果を記載します。


Google App Script の Version

Version 情報なんてあるのかとは思いましたが、
Relese Notes はあり、そこで機能の追加/削除情報はウォッチングできます。1
Release Notes  |  Apps Script  |  Google Developers

[1] Deprecated されるAPI のあるので、会社で使用している場合等は定期的に見た方がよいと感じました。


参考


muteHttpExceptionstrue を設定する

デフォルトだとエラーを吐きますが、muteHttpExceptionsのオプション設定で、
エラーを吐かずにHttpResponse を返してくれるようになります。
StackOverFlow のコードのコピペになりますが、以下のように記述できます。

var payload = {"value": "key"};
var response = UrlFetchApp.fetch(
            url,
            {
              method: "PUT",
              contentType: "application/json",
              payload: JSON.stringify(payload),
              muteHttpExceptions: true,
            }
          );
var responseCode = response.getResponseCode();
var responseBody = response.getContentText();

if (responseCode === 200) {
  var responseJson = JSON.parse(responseBody);
  // ...
} else {
  Logger.log(Utilities.formatString("Request failed. Expected 200, got %d: %s", responseCode, responseBody));
  // ...
}

try~catch する

現在作成しているスクリプトではこちらの実装としました。

  var errors = new Array();
  for each (var sitemapUrl in sitemapUrls) {
    for each (var target in pingTargets) { 
      try {
        var requestUrl = target + "?sitemap=";
        var requestUrl = requestUrl + encodeURIComponent(sitemapUrl);
        info("URL:>>>" + sitemapUrl + "|Target:>>>" + target);
        // GETリクエスト
        var response = UrlFetchApp.fetch(requestUrl);
        info("ResponseCode:>>" + response.getResponseCode());
      } catch (ex) {
        errors.push("Message: " + ex.message + "\r\nFile: " + ex.fileName + "\r\nLine: " + ex.lineNumber + "\r\n");
      }
    }
  }
  if(errors.length > 0) {
      var recipients = getColumValues("config", "C", 1);
      sendEmails(recipients, "Ping sitemap error report", errors.join("\r\n"));
  }

例外をcatch 後は、ex.fileName とか、ex.lineNumber 等で、例外が発生した情報が取得できます。
ex.message を出力しておけば大概のことはわかりそうです。


muteHttpExceptionstrue を設定してもExceptionは発生する

muteHttpExceptionstrue を設定していてもexceptionが発生するケースがあります。
google apps script - UrlFetchApp muteHttpException doesnt work - Stack Overflow
にも記載されていますが、URLが不正であったり、DNS エラーが発生すると、exception がスローされます。
実際にexception でスケジュール実行中のスクリプトがエラーを吐いて落ちていました。

テストスクリプトを作成して、exception 発生時のメッセージを記録してみました。
テストスクリプトでは、
Google Apps ScriptのUrlFetchAppでSSL証明書のエラーを回避する | ハックノート
を参考に"validateHttpsCertificates" : false を設定して、自己証明書の場合のエラーを回避しています。

DNSエラー

  • 実装
    function testUrlFetchAppDNSError() {
      var url = "https://localhost.unknown";
      var options = {
        "muteHttpExceptions" : true,
        "validateHttpsCertificates" : false,
        "followRedirects" : false,
      }
      try {
        var response = UrlFetchApp.fetch(url, options);
        Logger.info(url + ":responscode>>>" + response.getResponseCode()); 
      } catch(e) {
        Logger.log("message:" + e.message + "\nfileName:" + e.fileName + "\nlineNumber:" + e.lineNumber + "\nstack:" + e.stack);
      }
    }
    
  • 実装
[17-09-01 22:08:07:237 JST] message:DNS エラー: https://localhost.unknown
fileName:コード
lineNumber:22
stack:  at コード:22 (testUrlFetchAppDNSError)

不正なURL

  • 実装

    function testInvalidURL() {
      var url = "https://^/localhost.com";
      var options = {
        "muteHttpExceptions" : true,
        "validateHttpsCertificates" : false,
        "followRedirects" : false,
      }
      try {
        var response = UrlFetchApp.fetch(url, options);
        Logger.info(url + ":responscode>>>" + response.getResponseCode()); 
      } catch(e) {
        Logger.log("message:" + e.message + "\nfileName:" + e.fileName + "\nlineNumber:" + e.lineNumber + "\nstack:" + e.stack);
      }
    }
    

  • エラーログ

    [17-09-01 22:31:39:835 JST] message:無効な引数: https://^/localhost.com
    fileName:コード
    lineNumber:22
    stack:  at コード:22 (testInvalidURL)
    

使用できないアドレス

これは、実際スクリプトをスケジューラ実行している際に発生していました。
アクセスしているURL からの応答がなくしばらく待ったあとに、エラーが発生しています。
推測ではありますが、アクセス拒否されている場合に発生しているように思われます。

  • 実装

    function testUrlFetchAppUnsedAddress() {
      var url = "https://localhost.com";
      var options = {
        "muteHttpExceptions" : true,
        "validateHttpsCertificates" : false,
        "followRedirects" : false,
      }
      try {
        var response = UrlFetchApp.fetch(url, options);
        Logger.info(url + ":responscode>>>" + response.getResponseCode()); 
      } catch(e) {
        Logger.log("message:" + e.message + "\nfileName:" + e.fileName + "\nlineNumber:" + e.lineNumber + "\nstack:" + e.stack);
      }
    }
    

  • エラーログ

    [17-09-01 22:06:19:125 JST] message:使用できないアドレス: https://localhost.com
    fileName:コード
    lineNumber:22
    stack:  at コード:22 (testUrlFetchAppDNSError)
    

Exception が発生しても処理を続行させたいケース等は、"muteHttpExceptions" : true だけでなく、try~catch もしたほうがいいようです。
以上です。

コメント