Google Apps脚本urlfetchapp返回未经授权错误401
因此,我使用的是一个Google电子表格,该电子表格持有受保护的范围,因此可以完成排序行,从表格中调用Unbound Web应用程序:
Google Sheet XYZ -> Unbound Web App (sort code) -> Google Sheet XYZ
Unbound Web应用程序在我的帐户下运行,并使用Sheet Xyz与用户共享。 完美工作。
现在,我试图使用onsubmit
从Google表单中调用同一Web应用程序:
Google Form ABC -> Unbound Web App (sort code) -> Google Sheet XYZ
但是,EN例外Si从Web应用程序中返回:
{ [Exception: Request failed for https://script.google.com returned code 401. Truncated server response: <HTML>
<HEAD>
<TITLE>Unauthorized</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Unauthorized</H1>
<H2>Error 401</H2>
</BODY>
</HTML>
(use muteHttpExceptions option to examine full response)] name: 'Exception' }
奇怪的是,尽管我都是表单,Web应用程序,和表所有者....还尝试将其他范围添加到表单脚本中。
这是在表单的onsubmit
中运行的代码:
function callWebApp(){
var queryString = "?action=sort&sheetID="+contactListSSID+"&sortType=byName&sheetName="+S_PARENTS_SHEET_NAME+"&firstDataRow="+S_PARENTS_FIRST_DATA_ROW+"&colUserName="+S_PARENTS_NAME_SURNAME_COLUMN+"&classColSection="+null+"&colDOB="+null; // null because unused for this sort type
var baseUrl ="https://script.google.com/a/macros/ourdomain.com/s/xxxxxxx/exec"
var url = encodeURI(baseUrl + queryString).replace("#","%23");
var params = {method: "get", headers: {'Authorization': 'Bearer ' + ScriptApp.getOAuthToken()}};
try {
var request = UrlFetchApp.fetch(url,params)
Logger.log(request);
} catch (error) {
console.error(error);
return error;
}
return request;
}
未结合的Web应用程序代码(不包括代码中列出的所有操作):
function doGet(e) {
var param = e.queryString;
var parameters = param.split("&")
var validActions = ["sort", "duplicate", "delete"];
if (param == null){
return "Missing parameters";
}
param = e.parameter;
const matches = parameters.filter(s => s.includes('action'));
if (matches.length < 1 || validActions.indexOf(param.action) < 0){
return "Missing or bad action";
}
var ret;
switch(param.action){
case "sort":
ret = sortSheet(e);
break;
case "duplicate":
ret = duplicateSheet(e);
break;
case "delete":
ret = deleteSheet(e);
break;
}
return ContentService.createTextOutput(ret);
}
function sortSheet (e){
param = e.parameter;
var sheetId = param.sheetID;
var name = param.sheetName;
var sortType = param.sortType;
var COL_STUDENT_NAME = Number(param.colUserName);
var S_CLASS_COL_SECTION = Number(param.classColSection);
var COL_DOB = Number(param.colDOB);
var FIRST_DATA_ROW = Number(param.firstDataRow);
try{
var ss = SpreadsheetApp.openById(sheetId)
var sheet = ss.getSheetByName(name)
var dataRange = sheet.getRange(FIRST_DATA_ROW,1,(sheet.getLastRow() - FIRST_DATA_ROW + 1),sheet.getMaxColumns());
var a1 = dataRange.getA1Notation();
switch (sortType){
case "byName":
dataRange.sort({column: COL_STUDENT_NAME, ascending: true});
break;
case "bySection":
dataRange.sort([{column: S_CLASS_COL_SECTION, ascending: true}, {column: COL_STUDENT_NAME, ascending: true}]);
break;
case "byDOB":
dataRange.sort([{column: COL_DOB, ascending: true}, {column: COL_STUDENT_NAME, ascending: true}]);
break;
}
}
catch (err){
return err;
}
return a1;
}
当从电子表格中运行上述代码时,则可以使用。一旦以表单运行相同的代码,它将引发异常。
So, I am using a Google Spreadsheet which holds protected ranges, therefore, to accomplish sorting rows, an unbound web app is invoked from the sheet:
Google Sheet XYZ -> Unbound Web App (sort code) -> Google Sheet XYZ
Unbound Web App runs under my account and is shared with users using Sheet XYZ.
Works perfectly.
Now, I am attempting to invoke the same Web App from a Google Form using OnSubmit
:
Google Form ABC -> Unbound Web App (sort code) -> Google Sheet XYZ
however en exception si returned from the web app:
{ [Exception: Request failed for https://script.google.com returned code 401. Truncated server response: <HTML>
<HEAD>
<TITLE>Unauthorized</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Unauthorized</H1>
<H2>Error 401</H2>
</BODY>
</HTML>
(use muteHttpExceptions option to examine full response)] name: 'Exception' }
Strange to say this occurs although I am both the form, web app, and sheet owner.... Also tried to add other scopes to the Form script.
This is the code running in the form's OnSubmit
:
function callWebApp(){
var queryString = "?action=sort&sheetID="+contactListSSID+"&sortType=byName&sheetName="+S_PARENTS_SHEET_NAME+"&firstDataRow="+S_PARENTS_FIRST_DATA_ROW+"&colUserName="+S_PARENTS_NAME_SURNAME_COLUMN+"&classColSection="+null+"&colDOB="+null; // null because unused for this sort type
var baseUrl ="https://script.google.com/a/macros/ourdomain.com/s/xxxxxxx/exec"
var url = encodeURI(baseUrl + queryString).replace("#","%23");
var params = {method: "get", headers: {'Authorization': 'Bearer ' + ScriptApp.getOAuthToken()}};
try {
var request = UrlFetchApp.fetch(url,params)
Logger.log(request);
} catch (error) {
console.error(error);
return error;
}
return request;
}
Unbound Web App code (does not include all actions listed in the code):
function doGet(e) {
var param = e.queryString;
var parameters = param.split("&")
var validActions = ["sort", "duplicate", "delete"];
if (param == null){
return "Missing parameters";
}
param = e.parameter;
const matches = parameters.filter(s => s.includes('action'));
if (matches.length < 1 || validActions.indexOf(param.action) < 0){
return "Missing or bad action";
}
var ret;
switch(param.action){
case "sort":
ret = sortSheet(e);
break;
case "duplicate":
ret = duplicateSheet(e);
break;
case "delete":
ret = deleteSheet(e);
break;
}
return ContentService.createTextOutput(ret);
}
function sortSheet (e){
param = e.parameter;
var sheetId = param.sheetID;
var name = param.sheetName;
var sortType = param.sortType;
var COL_STUDENT_NAME = Number(param.colUserName);
var S_CLASS_COL_SECTION = Number(param.classColSection);
var COL_DOB = Number(param.colDOB);
var FIRST_DATA_ROW = Number(param.firstDataRow);
try{
var ss = SpreadsheetApp.openById(sheetId)
var sheet = ss.getSheetByName(name)
var dataRange = sheet.getRange(FIRST_DATA_ROW,1,(sheet.getLastRow() - FIRST_DATA_ROW + 1),sheet.getMaxColumns());
var a1 = dataRange.getA1Notation();
switch (sortType){
case "byName":
dataRange.sort({column: COL_STUDENT_NAME, ascending: true});
break;
case "bySection":
dataRange.sort([{column: S_CLASS_COL_SECTION, ascending: true}, {column: COL_STUDENT_NAME, ascending: true}]);
break;
case "byDOB":
dataRange.sort([{column: COL_DOB, ascending: true}, {column: COL_STUDENT_NAME, ascending: true}]);
break;
}
}
catch (err){
return err;
}
return a1;
}
When the above code is run from the spreadsheet, it works. Once the same code is run in the form, it will throw an exception.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题:
为了访问非公开应用脚本Web应用程序,需要
驱动器
范围。解决方案:
添加这两个范围中的任何一个都可以工作:
您可以添加它们在示例中明确
oauthscopes
:或者,更容易,您可以使用需要此范围的方法添加一个注释的行,例如:
脚本会注意到这一点,因此
script> scriptapp.getoauthtoken()
>将获得此范围的授权。相关:
Issue:
A
drive
scope is needed in order to access non-public Apps Script web apps.Solution:
Adding any of these two scopes will work:
You can either add them explicitly in the manifest, using the field
oauthScopes
:Or, more easily, you can add a commented line with a method that requires this scope, for example:
The script will notice this and so
ScriptApp.getOAuthToken()
will be authorized with this scope.Related: