Javascript 不能';在对象中找不到脚本回调函数

Javascript 不能';在对象中找不到脚本回调函数,javascript,google-apps-script,oauth,callback,Javascript,Google Apps Script,Oauth,Callback,我从谷歌使用,以设置与Spotify的连接。有一个问题。当createService()和authCallback()是auth对象的一部分时,引发错误: 找不到脚本函数:authCallback() 为什么在auth对象中回调函数不可见 此案例的代码为: function doGet() { if (auth.hasAccess()) { main(); } else { return auth.createFlow(); } } co

我从谷歌使用,以设置与Spotify的连接。有一个问题。当
createService()
authCallback()
auth
对象的一部分时,引发错误:

找不到脚本函数:
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();
    }
}
带错误的完整代码
函数doGet(){
if(auth.hasAccess()){
main();
}否则{
返回auth.createFlow();
}
}
常量auth=(函数(){
const CLIENT_ID='…';
const CLIENT_SECRET='…';
const_service=createService();
函数createService(){
返回OAuth2.createService('spotify')
.setAuthorizationBaseUrl('https://accounts.spotify.com/authorize')
.setTokenUrl('https://accounts.spotify.com/api/token')
.setClientId(客户端ID)
.setClientSecret(客户端密码)
.setCallbackFunction('authCallback')
.setPropertyStore(PropertiesService.getUserProperties())
.setScope('playlist-read-private playlist modify private playlist modify public user library read')
.setParam('响应类型','代码')
.setParam('redirect_uri',getRedirectUri());
}
函数authCallback(请求){
让isAuthorized=\u service.handleCallback(请求);
如果(未授权){
返回HtmlService.createHtmlOutput('成功!您可以关闭此选项卡');
}否则{
返回HtmlService.createHtmlOutput('Denied.youcan close this tab');
}
}
函数getRedirectUri(){
让scriptId=encodeURIComponent(ScriptApp.getScriptId());
让我们来看看https://script.google.com/macros/d/%s/usercallback';
返回Utilities.formatString(模板,scriptId);
}
函数hasAccess(){
return _service.hasAccess();
}
函数getAccessToken(){
return_service.getAccessToken();
}
函数createFlow(){
让模板=“”;
让html=Utilities.formatString(模板,_service.getAuthorizationUrl());
返回HtmlService.createHtmlOutput(html);
}
返回{
hasAccess:hasAccess,
getAccessToken:getAccessToken,
createFlow:createFlow,
};
})();

传递到
setCallbackFunction()
的值实际上被传递到方法中,该方法不要求参数在全局范围内可用。但这意味着您需要传递字符串“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
    };
})();
const auth=(函数(){
const CLIENT_ID='…';
const CLIENT_SECRET='…';
const_service=createService();
函数createService(){
返回OAuth2.createService('spotify')
.setAuthorizationBaseUrl('https://accounts.spotify.com/authorize')
.setTokenUrl('https://accounts.spotify.com/api/token')
.setClientId(客户端ID)
.setClientSecret(客户端密码)
.setCallbackFunction('auth.authCallback')//使用正确的方法名
.setPropertyStore(PropertiesService.getUserProperties())
.setScope('playlist-read-private playlist modify private playlist modify public user library read')
.setParam('响应类型','代码')
.setParam('redirect_uri',getRedirectUri());
}
函数authCallback(请求){
让isAuthorized=\u service.handleCallback(请求);
如果(未授权){
返回HtmlService.createHtmlOutput('成功!您可以关闭此选项卡');
}否则{
返回HtmlService.createHtmlOutput('Denied.youcan close this tab');
}
}
函数getRedirectUri(){
让scriptId=encodeURIComponent(ScriptApp.getScriptId());
让我们来看看https://script.google.com/macros/d/%s/usercallback';
返回Utilities.formatString(模板,scriptId);
}
函数hasAccess(){
return _service.hasAccess();
}
函数getAccessToken(){
return_service.getAccessToken();
}
函数createFlow(){
让模板=“”;
让html=Utilities.formatString(模板,_service.getAuthorizationUrl());
返回HtmlService.createHtmlOutput(html);
}
返回{
hasAccess:hasAccess,
getAccessToken:getAccessToken,
createFlow:createFlow,
authCallback:authCallback//公开该方法
};
})();

为了帮助澄清
authCallback()
的用途,请尝试将其重命名为类似于
displayAuthSuccessOrFailure()
。它所做的只是向最终用户呈现一条成功或失败的消息。这可能会改变您对其公开/封装的看法。

如果您在
iLife
中不公开
authCallback
,调用者如何调用它?你到底想对谁隐藏它?在对象内部声明
authCallback
而不是在全局范围内这样做有什么好处?@Rubén封装:D请阅读
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
    };
})();