在对象中找不到脚本回调函数
Couldn't find script callback function inside object
我使用 Google 中的 OAuth library 来设置与 Spotify 的连接。有一个问题。当 createService()
和 authCallback()
是 auth
对象的一部分时,引发错误:
Couldn't find script function: authCallback()
为什么回调函数在 auth 对象中不可见?
本例代码:
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,
};
})();
但是如果在没有 auth
对象的情况下执行此操作,则不会出现错误和成功回调:
function createService() {
return OAuth2.createService('spotify')
.setCallbackFunction('authCallback')
// ...
}
function authCallback(request) {
// ...
}
我可以这样做,但是在 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,
};
})();
您传递给 setCallbackFunction()
的值实际上会传递给 StateTokenBuilder.withMethod()
方法,这不需要参数在全局范围内可用。但这意味着您需要将字符串 'auth.authCallback' 传递给它。简单地传递它 '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
};
})();
为了帮助阐明 authCallback()
的用途,请尝试将其重命名为 displayAuthSuccessOrFailure()
。它所做的只是向最终用户显示成功或失败消息。这可能会改变您对其 exposure/encapsulation.
的看法
我使用 Google 中的 OAuth library 来设置与 Spotify 的连接。有一个问题。当 createService()
和 authCallback()
是 auth
对象的一部分时,引发错误:
Couldn't find script function:
authCallback()
为什么回调函数在 auth 对象中不可见?
本例代码:
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,
};
})();
但是如果在没有 auth
对象的情况下执行此操作,则不会出现错误和成功回调:
function createService() {
return OAuth2.createService('spotify')
.setCallbackFunction('authCallback')
// ...
}
function authCallback(request) {
// ...
}
我可以这样做,但是在 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,
};
})();
您传递给 setCallbackFunction()
的值实际上会传递给 StateTokenBuilder.withMethod()
方法,这不需要参数在全局范围内可用。但这意味着您需要将字符串 'auth.authCallback' 传递给它。简单地传递它 '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
};
})();
为了帮助阐明 authCallback()
的用途,请尝试将其重命名为 displayAuthSuccessOrFailure()
。它所做的只是向最终用户显示成功或失败消息。这可能会改变您对其 exposure/encapsulation.