Правильная обработка двумерного массива значений в рекурсивной функции - PullRequest
1 голос
/ 07 ноября 2019

Я реализую пользовательскую функцию в скрипте приложений.

Чтобы разрешить использование функции в качестве формулы массива в Google Sheets, я использую следующий шаблон для функции:

function myfunction(input) {
  if (input.map) {                // Test whether input is an array.
    return input.map(myfunction); // Recurse over array if so.
  } else {
    // Handle individual values here...
  }
}

Это позволяет настраиваемой функции принимать диапазон в качестве входных данных в виде двумерного массива, а затем возвращает двумерный массив, который может переполниться в соответствующие ячейки. Это задокументировано здесь.

Однако с помощью приведенного ниже кода я не использую "input", я использую "url", который, как я считаю, является источником моих проблем. Я выдаю ошибку: Attribute provided with no value: url (line 5).

function getRedirect(url) {
  if (url.map) {
    return url.map(getRedirect);
  } else {
    var response = UrlFetchApp.fetch(url, {'followRedirects': false, 'muteHttpExceptions': false});
    var redirectUrl = response.getHeaders()['Location']; // undefined if no redirect, so...
    var responseCode = response.getResponseCode();
    if (redirectUrl) {                                   // ...if redirected...
      var nextRedirectUrl = getRedirect(redirectUrl);    // ...it calls itself recursively...
      Logger.log(url + " is redirecting to " + redirectUrl + ". (" + responseCode + ")");
      return nextRedirectUrl;
    } else {                                               // ...until it's not
      Logger.log(url + " is canonical. (" + responseCode + ")");
      return url;
    }
  }  
}

Что я могу сделать, чтобы это исправить?

1 Ответ

3 голосов
/ 07 ноября 2019

Я подозреваю, что вы неправильно обрабатываете значения, которые не являются действительными URL-адресами. Предполагая, что в вашем сценарии больше ничего нет, строка 5 содержит вызов UrlFetchApp.fetch(), который, как я считаю, является источником ошибки.

Вы должны выполнить дополнительную проверку ошибок до и во время вызова UrlFetchApp.fetch(). Вот модифицированная реализация, демонстрирующая то, что я предлагаю:

function getRedirect(url) {
  if (url.map) {
    return url.map(getRedirect);
  }

  // Return an empty string if url contains a non-string value or an empty string.
  if (typeof url != 'string' || url == '') {
    return '';
  }

  // Enclose the UrlFetchApp.fetch() call in a try/catch() block...
  try {
    var response = UrlFetchApp.fetch(url, {
        'followRedirects': false,
        'muteHttpExceptions': false
    });
  } catch(e) {
    // And return an empty string if the call fails
    // (e.g. if provided a non-empty, non-URL string).
    return '';
  }

  var redirectUrl = response.getHeaders()['Location'];
  var responseCode = response.getResponseCode();
  if (redirectUrl) {
    var nextRedirectUrl = getRedirect(redirectUrl);
    return nextRedirectUrl;
  }
  return url;
}

Несколько замечаний:

  • Выполните как можно больше проверки ошибок перед блоком try / catch,Гораздо быстрее обрабатывать неверный ввод перед вызовом UrlFetchApp.fetch(). Вызов метода fetch и ожидание его сбоя может занять заметно больше времени, особенно если вы обрабатываете большой диапазон.
  • Я удалил операторы журналирования, чтобы сделать пример чуть более лаконичным,но может быть целесообразно регистрировать условия ошибок и / или возвращать строки, которые вызывают ошибки, а не пустые строки.
  • Имя переменной не имеет значения (то есть input vs url)
  • Я удалил лишние else блоки, так как операторы return в любом случае завершают выполнение функции.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...