[英]Couldn't find script callback function inside object
I use OAuth library from Google in order to set connection with Spotify.我使用 Google 的OAuth 库来设置与 Spotify 的连接。 There is a problem.
有一个问题。 When
createService()
and authCallback()
is part of auth
object, raised error:当
createService()
和authCallback()
是auth
对象的一部分时,引发错误:
Couldn't find script function:
authCallback()
找不到脚本函数:
authCallback()
Why is the callback function not visible inside the auth object?为什么回调函数在 auth 对象内不可见?
The code for this case:这个案例的代码:
function doGet() {
if (auth.hasAccess()) {
main();
} else {
return auth.createFlow();
}
}
const auth = (function () {
const CLIENT_ID = '...';
const CLIENT_SECRET = '...';
const _service = createService();
function createService() {
return OAuth2.createService('spotify')
.setAuthorizationBaseUrl('https://accounts.spotify.com/authorize')
.setTokenUrl('https://accounts.spotify.com/api/token')
.setClientId(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
.setCallbackFunction('authCallback') // set callback
.setPropertyStore(PropertiesService.getUserProperties())
.setScope('playlist-read-private playlist-modify-private playlist-modify-public user-library-read')
.setParam('response_type', 'code')
.setParam('redirect_uri', getRedirectUri());
}
function authCallback(request) {
let isAuthorized = _service.handleCallback(request);
if (isAuthorized) {
return HtmlService.createHtmlOutput('Success! You can close this tab.');
} else {
return HtmlService.createHtmlOutput('Denied. You can close this tab');
}
}
...
return {
hasAccess: hasAccess,
getAccessToken: getAccessToken,
createFlow: createFlow,
};
})();
But if do this without auth
object, no error and success callback:但是如果在没有
auth
对象的情况下执行此操作,则不会出现错误和成功回调:
function createService() {
return OAuth2.createService('spotify')
.setCallbackFunction('authCallback')
// ...
}
function authCallback(request) {
// ...
}
I can do this, but then it makes no sense to hide implementation details in the auth
object:我可以这样做,但是在
auth
对象中隐藏实现细节是没有意义的:
const auth = (function () {
function createService() {
return OAuth2.createService('spotify')
.setCallbackFunction('authCallback')
// ...
}
function authCallback(request) {
// ...
}
return {
// ...
authCallback: authCallback,
};
})();
function authCallback(request) {
return auth.authCallback(request);
}
function doGet() {
if (auth.hasAccess()) {
main();
} else {
return auth.createFlow();
}
}
function doGet() {
if (auth.hasAccess()) {
main();
} else {
return auth.createFlow();
}
}
const auth = (function () {
const CLIENT_ID = '...';
const CLIENT_SECRET = '...';
const _service = createService();
function createService() {
return OAuth2.createService('spotify')
.setAuthorizationBaseUrl('https://accounts.spotify.com/authorize')
.setTokenUrl('https://accounts.spotify.com/api/token')
.setClientId(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
.setCallbackFunction('authCallback')
.setPropertyStore(PropertiesService.getUserProperties())
.setScope('playlist-read-private playlist-modify-private playlist-modify-public user-library-read')
.setParam('response_type', 'code')
.setParam('redirect_uri', getRedirectUri());
}
function authCallback(request) {
let isAuthorized = _service.handleCallback(request);
if (isAuthorized) {
return HtmlService.createHtmlOutput('Success! You can close this tab.');
} else {
return HtmlService.createHtmlOutput('Denied. You can close this tab');
}
}
function getRedirectUri() {
let scriptId = encodeURIComponent(ScriptApp.getScriptId());
let template = 'https://script.google.com/macros/d/%s/usercallback';
return Utilities.formatString(template, scriptId);
}
function hasAccess() {
return _service.hasAccess();
}
function getAccessToken() {
return _service.getAccessToken();
}
function createFlow() {
let template = '<a href="%s" target="_blank">Authorize</a>';
let html = Utilities.formatString(template, _service.getAuthorizationUrl());
return HtmlService.createHtmlOutput(html);
}
return {
hasAccess: hasAccess,
getAccessToken: getAccessToken,
createFlow: createFlow,
};
})();
The value you pass into setCallbackFunction()
actually gets passed into the StateTokenBuilder.withMethod()
method, which does not require the argument to be available in the global scope.您传递给
setCallbackFunction()
的值实际上会传递给StateTokenBuilder.withMethod()
方法,该方法不需要参数在全局范围内可用。 But that means you need to pass it the string 'auth.authCallback'.但这意味着您需要将字符串“auth.authCallback”传递给它。 Simply passing it 'authCallback' won't work because there is no function in the global scope with that name.
简单地传递它 'authCallback' 是行不通的,因为在全局范围内没有具有该名称的函数。
So then it also means that you need to expose authCallback
in your return statement so that it becomes available in the global scope as auth.authCallback
.那么这也意味着您需要在 return 语句中公开
authCallback
,以便它在全局范围内作为auth.authCallback
。
const auth = (function () {
const CLIENT_ID = '...';
const CLIENT_SECRET = '...';
const _service = createService();
function createService() {
return OAuth2.createService('spotify')
.setAuthorizationBaseUrl('https://accounts.spotify.com/authorize')
.setTokenUrl('https://accounts.spotify.com/api/token')
.setClientId(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
.setCallbackFunction('auth.authCallback') // Use correct method name
.setPropertyStore(PropertiesService.getUserProperties())
.setScope('playlist-read-private playlist-modify-private playlist-modify-public user-library-read')
.setParam('response_type', 'code')
.setParam('redirect_uri', getRedirectUri());
}
function authCallback(request) {
let isAuthorized = _service.handleCallback(request);
if (isAuthorized) {
return HtmlService.createHtmlOutput('Success! You can close this tab.');
} else {
return HtmlService.createHtmlOutput('Denied. You can close this tab');
}
}
function getRedirectUri() {
let scriptId = encodeURIComponent(ScriptApp.getScriptId());
let template = 'https://script.google.com/macros/d/%s/usercallback';
return Utilities.formatString(template, scriptId);
}
function hasAccess() {
return _service.hasAccess();
}
function getAccessToken() {
return _service.getAccessToken();
}
function createFlow() {
let template = '<a href="%s" target="_blank">Authorize</a>';
let html = Utilities.formatString(template, _service.getAuthorizationUrl());
return HtmlService.createHtmlOutput(html);
}
return {
hasAccess: hasAccess,
getAccessToken: getAccessToken,
createFlow: createFlow,
authCallback: authCallback // Expose the method
};
})();
Just to help clarify the purpose of authCallback()
, try renaming it to something like displayAuthSuccessOrFailure()
.只是为了帮助澄清
authCallback()
的目的,请尝试将其重命名为displayAuthSuccessOrFailure()
。 All it's doing is presenting a success or failure message to the end user.它所做的只是向最终用户显示成功或失败的消息。 This may alter how you think about its exposure/encapsulation.
这可能会改变您对其暴露/封装的看法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.