Как отправить код состояния ошибки, например, неверный запрос (400), из скрипта Google?

#javascript #google-apps-script #http-status-codes

#javascript #google-apps-script #http-status-codes

Вопрос:

Это doPost функция внутри приложения Google, которая возвращает сообщение Hello World.

 function doPost(e){

  return ContentService.createTextOutput('Hello World');
} 
 

Теперь предположим, что я хочу принимать только допустимый JSON для отправки в эту конечную точку приложения Google, и я хочу отправить ответ с неверным статусом запроса. Как я могу это сделать. Вот псевдокод:

 function doPost(e){
  try{
     const data = JSON.parse(e.postData.contents);
     return ContentService.createTextOutput('Hello World');
  }catch(err){
      // Send Bad Request
  }      

} 
 

Комментарии:

1. К сожалению, на текущем этапе ContentService невозможно изменить код состояния. Похоже, что это текущая спецификация. Итак, в вашей ситуации, как насчет возврата сообщения об ошибке, например ContentService.createTextOutput(JSON.stringify({error: 'Error message'})); ? И, например, когда вы возвращаете допустимое значение, как насчет ContentService.createTextOutput(JSON.stringify({value: 'value'})); ? Таким образом, вы можете проверить значение, используя ключ данных JSON. Если это было не то направление, которого вы ожидали, я приношу свои извинения.

2. @Tanaike это то, что я уже делаю. Но это просто уродливый взлом.

3. Спасибо, что ответили. О that's what I'm already doing. But it's just an ugly hack. , я глубоко извиняюсь за то, что мой комментарий не был полезен для вашей ситуации.

4. @Tanaike КСТАТИ, это, вероятно, полезно для других, кто изучает это (и спасибо!).). Я предлагаю вам опубликовать его в качестве ответа. У вас есть ссылка на текущую спецификацию этого?

5. Я отправил его в качестве ответа. Не могли бы вы подтвердить это, пожалуйста? Если у вас есть какие-либо замечания по модификации, пожалуйста, сообщите мне.

Ответ №1:

Проблема и обходной путь:

К сожалению, на текущем этапе ContentService невозможно изменить код состояния. Когда я увидел официальный документ класса ContentService, такой метод не может быть найден. Ref Похоже, что это текущая спецификация.

Итак, в вашей ситуации, в качестве текущего обходного пути, как насчет возврата значения в виде данных JSON? Таким образом, вы можете проверить значение, используя ключ данных JSON. Например, как насчет следующего примера сценария?

  • Когда возвращается правильное значение без ошибки,
       return ContentService.createTextOutput(JSON.stringify({value: 'value'}));
     
  • Когда возвращается значение с ошибкой,
       return ContentService.createTextOutput(JSON.stringify({error: 'Error message'}));
     
  • Когда вам нужно .setMimeType(ContentService.MimeType.JSON) , пожалуйста, добавьте это.

Примечание:

  • Когда я искал об этом в Google issue tracker, я не смог его найти. Итак, как насчет сообщения об этом как о будущем запросе? Ссылка

Ссылка:

Ответ №2:

Вот еще один обходной путь, который позволяет создавать ошибки на стороне клиента для ошибок на стороне веб-приложения. Например, клиенту может потребоваться перехватить ошибки, такие как неверные аргументы URL, отправленные в веб-приложение (например, вопрос OP), или перехватить ошибки, вызванные методом, который вызывается из doGet() или doPost() .

Насколько я знаю, когда ошибка выдается после doGet() or doPost() , в ответе возвращается текстовое сообщение об ошибке, но сам запрос веб-приложения выполняется успешно, поэтому на стороне клиента ошибка не выдается. Как сказал @Tanaike, разработчик веб-приложений Google по-прежнему не может выдать HTTP-ошибку из приложения (например 400 Bad Request , или 500 Internal Server Error ).

Идея заключается в возврате тела функции из веб-приложения, которое клиент может использовать для создания и запуска динамической функции через Function() конструктор (это предполагает, что Javascript доступен на клиенте).

Таким образом, веб-приложение может быть записано в:

  • возвращает тело функции, которое выдает ошибку из-за неверных аргументов, ошибок метода сервера и т. Д.
  • возвращает тело функции, которое будет возвращать предполагаемый JSON при отсутствии ошибки

Это немного взлом, но он унифицирует обработку ошибок на стороне клиента. Клиент выполняет http-запрос, создает функцию, используя тело функции, возвращенное в ответе, а затем запускает эту функцию, все в одном try{} блоке. Тогда в блоке могут быть обнаружены как ошибки http, вызванные Google, так и ошибки веб-приложения catch{} .

Пример настройки для клиента скрипта Google Apps, отправляющего запрос в веб-приложение Google:

(1) В веб-приложении doGet() или doPost() функции:

 // this string will be returned by the webapp
var fnBody;

// for bad url args, return a fnBody that will throw an error with an indicative message 
if(!urlArgsOk()) {
  fnBody =  "'use strict'; throw new Error('POST args error');";  
} 
// if url args are ok, call server method
else {
    try {
      // if the method call succeeds, return a fnBody that will return the intended JSON
      var returnObj = myServerMethod(methodArgs);
      fnBody = "'use strict'; return JSON.stringify("   JSON.stringify(returnObj)   ");";
    }
    catch(serverErr) {
      // if the method call fails, return a fnBody that will throw an error ...
      // ... simple example shown here, but info from serverErr can be included in fnBody
      fnBody =  "'use strict'; throw new Error('server error');";  
    } 
}    

// return fnBody, which can be run via Function() on the client
return ContentService.createTextOutput(fnBody).setMimeType(ContentService.MimeType.TEXT);
 

(2) На стороне клиента (клиент скрипта Google apps отправляет запрос POST)

 // Set the url, payload, and fetch options
var url = "https://script.google.com/_______/exec?arg1=val1amp;arg2=val2";
var payload = getPayloadString(); // whatever POST payload needs to be sent

var options = {
  'method' : 'POST',
  'contentType': 'application/json',
  'muteHttpExceptions': false, // let Google http exceptions come through
  'payload' : payload,
  'headers': {authorization: "Bearer "   ScriptApp.getOAuthToken()}
};

// Send a request to the web app
try {

  // make the POST request - this throws Google-generated HTTP errors if any
  var response = UrlFetchApp.fetch(url, options);

  // create the dynamic function from the fnBody returned
  var responseFn = new Function(response.getContentText());
  
  // run the function - this returns intended JSON content
  // or throws web app downstream errors if any
  var responseJson = responseFn();

}
catch(err) {
   // handle either source of error
   console.log(err.message);
}
 

Существуют потенциальные риски безопасности, связанные с динамическим кодом, поэтому я не уверен, насколько широко это может быть применимо. Я мог бы использовать это в приложении, которое полностью находится в частном домене GCP, т. Е. С веб-приложением, ограниченным пользователями одного домена, а клиентское приложение также в том же домене. Некоторую безопасность также добавляет 'use strict' директива, которая блокирует динамическую функцию, устанавливая для нее this значение undefined (ref). Но все же неплохо продумать последствия динамического кода (ref1, ref2).