如何从 google 脚本发送错误状态代码,如 Bad Request (400)?

How to send an error status code like Bad Request (400) from a google script?

这是 Google 应用中的一个 doPost 函数,returns 一个 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
  }      

} 

问题和解决方法:

很遗憾,在当前阶段,ContentService无法修改状态码。我看ClassContentService的官方文档,找不到这样的方法。 Ref 好像是现在的规格

那么在你的情况下,作为当前的解决方法,将值作为 JSON 数据返回怎么样?这样,您可以使用 JSON 数据的键检查值。例如,下面的示例脚本怎么样?

  • 当返回没有错误的正确值时,

      return ContentService.createTextOutput(JSON.stringify({value: 'value'}));
    
  • 返回错误值时,

      return ContentService.createTextOutput(JSON.stringify({error: 'Error message'}));
    
  • 需要.setMimeType(ContentService.MimeType.JSON)的时候请加这个

注:

  • 当我在 Google 问题跟踪器上搜索此内容时,我找不到它。那么将此报告为未来的请求怎么样? Ref

参考:

这是另一种解决方法,允许在客户端针对 Web 应用程序端的错误引发错误。例如,客户端可能需要捕获诸如发送到 Web 应用程序的错误 url args 之类的错误(即 OP 的问题),或者捕获从 doGet()doPost().

据我所知,当 doGet()doPost() 的下游抛出错误时,文本错误消息是 return 在响应中编辑的,但是网络应用程序请求本身成功,因此客户端不会抛出任何错误。正如@Tanaike 所说,Google 网络应用程序开发人员似乎仍然无法从应用程序中抛出 HTTP 错误(例如 400 Bad Request500 Internal Server Error)。

这个想法涉及 return 从 Web 应用程序创建一个函数体,客户端可以使用它来创建和 运行 通过 Function() 构造函数创建一个动态函数(假设 Javascript在客户端可用)。

因此网络应用程序可以写入:

  • return 一个函数体,它会因错误的参数、服务器方法错误等而抛出错误。
  • return 一个函数体,它将 return 在没有错误的情况下 JSON

这有点hack,但它统一了客户端的错误处理。客户端发出 http 请求,使用在响应中 returned 的函数体构建一个函数,然后 运行s 这个函数,所有这些都在一个 try{} 块中。然后 Google 引发的 http 错误和 Web 应用下游错误都可以在 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 应用程序脚本客户端发出 POST 请求)

// Set the url, payload, and fetch options
var url = "https://script.google.com/_______/exec?arg1=val1&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 域中的应用程序中使用它,即 Web 应用程序仅限于同域用户,而客户端应用程序也在同一个域中。 'use strict' 指令也增加了一些安全性,它通过将其 this 设置为 undefined (ref). But it's still a good idea to think through the dynamic code implications (ref1, ref2).

来封装动态函数