Google 应用程序脚本执行 API 服务授权每小时失败一次
Google apps script execution API service authorization fails once per hour
我大约每 1.5 分钟用我的 C# 应用程序执行一个 Google 应用程序脚本。应用程序脚本在电子表格之间移动内容,并编辑工作表。我也使用驱动器 API.
我的脚本长时间运行良好,除了我每小时有 5 分钟出现授权错误。
这是我处理授权的代码:
class Authentication
{
public static ScriptService ScriptsAuthenticateOauth(UserCredential credential)
{
try
{
ScriptService service = new ScriptService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "MyApp",
});
return service;
}
catch (Exception ex)
{
Console.WriteLine(DateTime.Now.ToString("HH:mm") + ": An authentication error occurred: " + ex.InnerException);
return null;
}
}
public static UserCredential getCredential(string clientId, string clientSecret, string userName)
{
string[] scopes = new string[] { DriveService.Scope.Drive, // view and manage your files and documents
DriveService.Scope.DriveAppdata, // view and manage its own configuration data
DriveService.Scope.DriveAppsReadonly, // view your drive apps
DriveService.Scope.DriveFile, // view and manage files created by this app
DriveService.Scope.DriveMetadataReadonly, // view metadata for files
DriveService.Scope.DriveReadonly, // view files and documents on your drive
DriveService.Scope.DriveScripts, // modify your app scripts
ScriptService.Scope.Drive,
"https://www.googleapis.com/auth/spreadsheets",
"https://spreadsheets.google.com/feeds",
"https://docs.google.com/feeds"};
return GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets { ClientId = clientId, ClientSecret = clientSecret }
, scopes
, userName
, CancellationToken.None
, new FileDataStore("Google.Sheet.Sync.Auth.Store")).Result;
}
public static DriveService DriveAuthenticateOauth(UserCredential credential)
{
try
{
DriveService service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "MyApp",
});
// Console.WriteLine("Auth success");
return service;
}
catch (Exception ex)
{
// Console.WriteLine(ex.InnerException);
Console.WriteLine(DateTime.Now.ToString("HH:mm") + ": An authentication error occurred: " + ex.InnerException);
return null;
}
}
}
我得到这样的服务:
var credential = Authentication.getCredential(CLIENT_ID, CLIENT_SECRET, Environment.UserName);
DriveService driveService = Authentication.DriveAuthenticateOauth(credential);
ScriptService scriptService = Authentication.ScriptsAuthenticateOauth(credential);
但在一小时结束时,应用程序脚本调用抛出以下错误:
Script error message: Authorization is required to perform that action.
需要说明的是,它在其他所有时间都有效,只是在接近小时结束的那 5 分钟内无效。我确实在我的开发者控制台上激活了 Google Drive API,并在应用程序脚本编辑器中的 Resources > Advanced Google services... 下。
这是怎么回事?这可以修复吗?
经过进一步研究,我发现脚本只需 运行 来自脚本编辑器即可防止此错误。这是我找到的信息:
Authorization is required to perform that action.
This error indicates that the script is lacking the authorization needed to run. When a script is run in the Script Editor or from a custom menu item an authorization dialog is presented to the user. However, when a script is run as a service, embedded with a Google Sites page, or run from a trigger the dialog cannot be presented and this error is shown. To authorize the script, open the Script Editor and run any function. To avoid this error, remember to run the script once in the Script Editor after adding new services or capabilities to your script.
来源:https://developers.google.com/apps-script/troubleshooting#common_errors
我对我的代码所做的另一个相关改进是在创建这两个服务中的每一个之前获取凭证对象的新副本:换句话说,我改变了这个:
var credential = Authentication.getCredential(CLIENT_ID, CLIENT_SECRET, Environment.UserName);
DriveService driveService = Authentication.DriveAuthenticateOauth(credential);
ScriptService scriptService = Authentication.ScriptsAuthenticateOauth(credential);
对此:
var credential = Authentication.getCredential(CLIENT_ID, CLIENT_SECRET, Environment.UserName);
DriveService driveService = Authentication.DriveAuthenticateOauth(credential);
credential = Authentication.getCredential(CLIENT_ID, CLIENT_SECRET, Environment.UserName);
ScriptService scriptService = Authentication.ScriptsAuthenticateOauth(credential);
这本身并没有解决我的问题,但它有助于避免 OAuth 怪癖,并且可以防止不必要的令牌刷新。
您可能需要一个刷新令牌。访问令牌通常从 Google 开始设置为仅存在 3600 秒(1 小时),而刷新令牌的寿命更长,旨在让您在前一个访问令牌过期时轻松获得新的访问令牌。这可能是一个很好的起点:Google API .NET Client information on token responses
此外,如果您没有刷新令牌,但有访问令牌,您可以撤销之前的访问令牌,然后再次进行身份验证。如果正确调用,新响应将有一个刷新令牌“确保您获得 "Bearer"
令牌类型。
有更多关于使用寿命更长的刷新令牌的信息here。
如果您的申请失败 "just in those 5 minutes near the end of the hour",您很可能遇到 this bug with the execution API。
显然,使用将在 6 分钟内过期的令牌请求执行 API 会产生 "Authorization is required..." 错误。这似乎与 6 分钟是脚本的最大 运行 时间有关。
如果您知道令牌何时过期(Android 不是这种情况),则可以提前刷新您的令牌。希望这个bug能尽快修复。
我不确定您是否真的解决了您的问题,或者您是否只是找到了一个好的解决方法,但您可能想为该 Apps 脚本问题加注星标,以便尽快解决它。
我大约每 1.5 分钟用我的 C# 应用程序执行一个 Google 应用程序脚本。应用程序脚本在电子表格之间移动内容,并编辑工作表。我也使用驱动器 API.
我的脚本长时间运行良好,除了我每小时有 5 分钟出现授权错误。
这是我处理授权的代码:
class Authentication
{
public static ScriptService ScriptsAuthenticateOauth(UserCredential credential)
{
try
{
ScriptService service = new ScriptService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "MyApp",
});
return service;
}
catch (Exception ex)
{
Console.WriteLine(DateTime.Now.ToString("HH:mm") + ": An authentication error occurred: " + ex.InnerException);
return null;
}
}
public static UserCredential getCredential(string clientId, string clientSecret, string userName)
{
string[] scopes = new string[] { DriveService.Scope.Drive, // view and manage your files and documents
DriveService.Scope.DriveAppdata, // view and manage its own configuration data
DriveService.Scope.DriveAppsReadonly, // view your drive apps
DriveService.Scope.DriveFile, // view and manage files created by this app
DriveService.Scope.DriveMetadataReadonly, // view metadata for files
DriveService.Scope.DriveReadonly, // view files and documents on your drive
DriveService.Scope.DriveScripts, // modify your app scripts
ScriptService.Scope.Drive,
"https://www.googleapis.com/auth/spreadsheets",
"https://spreadsheets.google.com/feeds",
"https://docs.google.com/feeds"};
return GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets { ClientId = clientId, ClientSecret = clientSecret }
, scopes
, userName
, CancellationToken.None
, new FileDataStore("Google.Sheet.Sync.Auth.Store")).Result;
}
public static DriveService DriveAuthenticateOauth(UserCredential credential)
{
try
{
DriveService service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "MyApp",
});
// Console.WriteLine("Auth success");
return service;
}
catch (Exception ex)
{
// Console.WriteLine(ex.InnerException);
Console.WriteLine(DateTime.Now.ToString("HH:mm") + ": An authentication error occurred: " + ex.InnerException);
return null;
}
}
}
我得到这样的服务:
var credential = Authentication.getCredential(CLIENT_ID, CLIENT_SECRET, Environment.UserName);
DriveService driveService = Authentication.DriveAuthenticateOauth(credential);
ScriptService scriptService = Authentication.ScriptsAuthenticateOauth(credential);
但在一小时结束时,应用程序脚本调用抛出以下错误:
Script error message: Authorization is required to perform that action.
需要说明的是,它在其他所有时间都有效,只是在接近小时结束的那 5 分钟内无效。我确实在我的开发者控制台上激活了 Google Drive API,并在应用程序脚本编辑器中的 Resources > Advanced Google services... 下。
这是怎么回事?这可以修复吗?
经过进一步研究,我发现脚本只需 运行 来自脚本编辑器即可防止此错误。这是我找到的信息:
Authorization is required to perform that action.
This error indicates that the script is lacking the authorization needed to run. When a script is run in the Script Editor or from a custom menu item an authorization dialog is presented to the user. However, when a script is run as a service, embedded with a Google Sites page, or run from a trigger the dialog cannot be presented and this error is shown. To authorize the script, open the Script Editor and run any function. To avoid this error, remember to run the script once in the Script Editor after adding new services or capabilities to your script.
来源:https://developers.google.com/apps-script/troubleshooting#common_errors
我对我的代码所做的另一个相关改进是在创建这两个服务中的每一个之前获取凭证对象的新副本:换句话说,我改变了这个:
var credential = Authentication.getCredential(CLIENT_ID, CLIENT_SECRET, Environment.UserName);
DriveService driveService = Authentication.DriveAuthenticateOauth(credential);
ScriptService scriptService = Authentication.ScriptsAuthenticateOauth(credential);
对此:
var credential = Authentication.getCredential(CLIENT_ID, CLIENT_SECRET, Environment.UserName);
DriveService driveService = Authentication.DriveAuthenticateOauth(credential);
credential = Authentication.getCredential(CLIENT_ID, CLIENT_SECRET, Environment.UserName);
ScriptService scriptService = Authentication.ScriptsAuthenticateOauth(credential);
这本身并没有解决我的问题,但它有助于避免 OAuth 怪癖,并且可以防止不必要的令牌刷新。
您可能需要一个刷新令牌。访问令牌通常从 Google 开始设置为仅存在 3600 秒(1 小时),而刷新令牌的寿命更长,旨在让您在前一个访问令牌过期时轻松获得新的访问令牌。这可能是一个很好的起点:Google API .NET Client information on token responses
此外,如果您没有刷新令牌,但有访问令牌,您可以撤销之前的访问令牌,然后再次进行身份验证。如果正确调用,新响应将有一个刷新令牌“确保您获得 "Bearer"
令牌类型。
有更多关于使用寿命更长的刷新令牌的信息here。
如果您的申请失败 "just in those 5 minutes near the end of the hour",您很可能遇到 this bug with the execution API。
显然,使用将在 6 分钟内过期的令牌请求执行 API 会产生 "Authorization is required..." 错误。这似乎与 6 分钟是脚本的最大 运行 时间有关。
如果您知道令牌何时过期(Android 不是这种情况),则可以提前刷新您的令牌。希望这个bug能尽快修复。
我不确定您是否真的解决了您的问题,或者您是否只是找到了一个好的解决方法,但您可能想为该 Apps 脚本问题加注星标,以便尽快解决它。