gapi 未定义 - 与 gapi.auth2.init 相关的 Google 登录问题
Posted
技术标签:
【中文标题】gapi 未定义 - 与 gapi.auth2.init 相关的 Google 登录问题【英文标题】:gapi is not defined - Google sign in issue with gapi.auth2.init 【发布时间】:2015-09-17 15:21:05 【问题描述】:我正在尝试实施 Google 登录并检索用户的个人资料信息。 错误是:Uncaught ReferenceError: gapi is not defined。这是为什么呢?
<!doctype html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://apis.google.com/js/platform.js" async defer></script>
<script type="text/javascript">
$(function()
gapi.auth2.init(
client_id: 'filler_text_for_client_id.apps.googleusercontent.com'
);
);
</head>
<body>
</body>
</html>
【问题讨论】:
【参考方案1】:这是因为您的脚本标签上有async
和defer
属性。 gapi
将在带有 gapi.auth2.init
的脚本标记之后加载...
要在执行此代码之前等待gapi
,您可以在脚本标签中使用 onload 查询参数,如下所示:
<script src="https://apis.google.com/js/platform.js?onload=onLoadCallback" async defer></script>
<script>
window.onLoadCallback = function()
gapi.auth2.init(
client_id: 'filler_text_for_client_id.apps.googleusercontent.com'
);
</script>
或者,如果你在很多地方都需要它,你可以使用 Promise 来更好地构建它:
// promise that would be resolved when gapi would be loaded
var gapiPromise = (function()
var deferred = $.Deferred();
window.onLoadCallback = function()
deferred.resolve(gapi);
;
return deferred.promise()
());
var authInited = gapiPromise.then(function()
gapi.auth2.init(
client_id: 'filler_text_for_client_id.apps.googleusercontent.com'
);
)
$('#btn').click(function()
gapiPromise.then(function()
// will be executed after gapi is loaded
);
authInited.then(function()
// will be executed after gapi is loaded, and gapi.auth2.init was called
);
);
【讨论】:
那我应该在哪里添加 onSignOut 函数呢?它也需要gapi,但我只在用户点击按钮时调用它 您也可以将其添加到onLoadCallback
,例如将$(function() .... )
放在那里..
这是我尝试的第一件事。对不起,我之前没有提到它。尝试调用 signOut 会导致“未捕获的 ReferenceError:未定义 signOut”
哦等等,没关系。你在谈论 document.ready 功能大声笑。等一下,我试试看。
添加了如何使用 Promise 构建它的示例【参考方案2】:
我想你会在上面的例子中发现这也行不通,因为gapi.auth2
还没有被定义(我知道这一点是因为我自己今天犯了同样的错误)你首先需要调用@ 987654322@ 并传递一个回调,然后调用gapi.auth2.init
。这是我的_onGoogleLoad
函数的示例,它是加载第一个platform.js
脚本的回调。
var _auth2
var _onGoogleLoad = function ()
gapi.load('auth2', function ()
_auth2 = gapi.auth2.init(
client_id: 'OUR_REAL_ID_GOES_HERE',
scope: 'email',
fetch_basic_profile: false
)
_enableGoogleButton()
)
之后,您可以使用_auth2
变量来实际登录用户。
【讨论】:
谢谢你的回答,我试试看! 或者你包括一个<div class="g-signin2" data-onsuccess="onSignIn"></div>
(等等)按钮,如文档中所述。如果存在,platform.js 将自动下载auth2
。这似乎触发了完全相同的内容被下载。不幸的是,文档在这方面不是很好。此外,index.html 中的<script>
可以是https://apis.google.com/js/api.js
,而不是您的情况下的platform.js
,它包含的代码更少。
@phil294 有没有办法抑制这种行为?
@beppe9000 我不知道,对不起【参考方案3】:
问题不仅在gapi
。要调用 init
方法 - 必须初始化 auth2 对象。
一旦 google auth 对象完全初始化,就有一个承诺GoogleAuth.then(onInit, onFailure)
gapi.load('auth2', initSigninV2);
function initSigninV2()
gapi.auth2.init(
client_id: 'CLIENT_ID.apps.googleusercontent.com'
).then(function (authInstance)
// now auth2 is fully initialized
);
【讨论】:
我只需要这个 这应该是公认的答案!如果您使用的是 Vue.js 并且您使用单独的组件进行注销,则可以使用! 你拯救了我的一天!这是正确的答案。谢谢。万岁!【参考方案4】:虽然这些答案对我有所帮助,但我相信官方文档中有更好的答案。
见Integrating Google Sign-In using listeners
var auth2; // The Sign-In object.
var googleUser; // The current user.
/**
* Calls startAuth after Sign in V2 finishes setting up.
*/
var appStart = function()
gapi.load('auth2', initSigninV2);
;
/**
* Initializes Signin v2 and sets up listeners.
*/
var initSigninV2 = function()
auth2 = gapi.auth2.init(
client_id: 'CLIENT_ID.apps.googleusercontent.com',
scope: 'profile'
);
// Listen for sign-in state changes.
auth2.isSignedIn.listen(signinChanged);
// Listen for changes to current user.
auth2.currentUser.listen(userChanged);
// Sign in the user if they are currently signed in.
if (auth2.isSignedIn.get() == true)
auth2.signIn();
// Start with the current live values.
refreshValues();
;
/**
* Listener method for sign-out live value.
*
* @param boolean val the updated signed out state.
*/
var signinChanged = function (val)
console.log('Signin state changed to ', val);
document.getElementById('signed-in-cell').innerText = val;
;
/**
* Listener method for when the user changes.
*
* @param GoogleUser user the updated user.
*/
var userChanged = function (user)
console.log('User now: ', user);
googleUser = user;
updateGoogleUser();
document.getElementById('curr-user-cell').innerText =
JSON.stringify(user, undefined, 2);
;
/**
* Updates the properties in the Google User table using the current user.
*/
var updateGoogleUser = function ()
if (googleUser)
document.getElementById('user-id').innerText = googleUser.getId();
document.getElementById('user-scopes').innerText =
googleUser.getGrantedScopes();
document.getElementById('auth-response').innerText =
JSON.stringify(googleUser.getAuthResponse(), undefined, 2);
else
document.getElementById('user-id').innerText = '--';
document.getElementById('user-scopes').innerText = '--';
document.getElementById('auth-response').innerText = '--';
;
/**
* Retrieves the current user and signed in states from the GoogleAuth
* object.
*/
var refreshValues = function()
if (auth2)
console.log('Refreshing values...');
googleUser = auth2.currentUser.get();
document.getElementById('curr-user-cell').innerText =
JSON.stringify(googleUser, undefined, 2);
document.getElementById('signed-in-cell').innerText =
auth2.isSignedIn.get();
updateGoogleUser();
【讨论】:
【参考方案5】:对于 Vue.JS 应用程序
为platform.js
的脚本标签添加一个 onload 挂钩
设置调度事件的函数
在组件的 mounted
挂钩中捕获该事件。
这是一个相当完整的示例,您可以将其粘贴到新的 vue-cli
项目中。
别忘了提供您自己的客户 ID!
public/index.html
<script type="text/javascript">
function triggerGoogleLoaded()
window.dispatchEvent(new Event("google-loaded"));
</script>
<script
src="https://apis.google.com/js/platform.js?onload=triggerGoogleLoaded"
async
defer
></script>
<meta
name="google-signin-client_id"
content="xxxxxxxxxxxx.apps.googleusercontent.com"
/>
App.vue
<template>
<div id="app">
<div id="nav">
<div id="google-signin-btn"></div>
<a href="#" class="sign-out" @click="signOut" v-if="profile">Sign out</a>
</div>
<div v-if="profile" class="">
<h2>Signed In User Profile</h2>
<pre> profile </pre>
</div>
<div v-if="!profile">
<h2>Signed out.</h2>
</div>
<router-view />
</div>
</template>
<script>
export default
components: ,
data()
return
profile: false
;
,
methods:
onSignIn(user)
const profile = user.getBasicProfile();
this.profile = profile;
,
signOut()
var auth2 = gapi.auth2.getAuthInstance();
auth2.signOut().then(() =>
location.reload(true);
);
,
renderGoogleLoginButton()
gapi.signin2.render("google-signin-btn",
onsuccess: this.onSignIn
);
,
mounted()
window.addEventListener("google-loaded", this.renderGoogleLoginButton);
;
</script>
【讨论】:
【参考方案6】:这对我有用: https://***.com/a/55314602/1034622
包含这个脚本标签
<script src="https://apis.google.com/js/platform.js"></script>
【讨论】:
这是缩小版:<script src='https://apis.google.com/js/api.js'></script>
【参考方案7】:
廉价修复是:
通过使用告诉 Eslint 这是一个全局变量
/* global gapi */
【讨论】:
这个问题和eslint没有任何关系,错误也不是来自eslint;这是一个 JavaScript 运行时错误。以上是关于gapi 未定义 - 与 gapi.auth2.init 相关的 Google 登录问题的主要内容,如果未能解决你的问题,请参考以下文章
Google Plus API错误gapi.loaded_0
AdWords 范围:使用 OAuth 流程进行身份验证后缺少 gapi.client.adwords。找不到要传递给 gapi.client.request() 的路径变量