gapi 未定义 - Google gapi 登录问题。auth2.init
gapi is not defined - Google sign in issue with gapi.auth2.init
我正在尝试实现 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>
这是因为您的脚本标签上有 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>
或者当你在很多地方需要它的时候,你可以使用 promises 来更好地构造它:
// 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
});
});
我想你会发现上面的例子也行不通,因为 gapi.auth2
还没有定义(我知道这一点是因为我自己也犯了同样的错误,今天)你先需要调用 gapi.load('auth2', callback)
并传递一个回调,然后调用 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
变量来实际登录用户。
虽然这些答案对我有帮助,但我相信官方文档中有更好的答案。
见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();
}
}
问题不仅在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
});
}
这对我有用:
包括这个脚本标签
<script src="https://apis.google.com/js/platform.js"></script>
对于 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>
便宜的修复是:
告诉 Eslint 这是一个全局变量,使用
/* global gapi */
我正在尝试实现 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>
这是因为您的脚本标签上有 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>
或者当你在很多地方需要它的时候,你可以使用 promises 来更好地构造它:
// 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
});
});
我想你会发现上面的例子也行不通,因为 gapi.auth2
还没有定义(我知道这一点是因为我自己也犯了同样的错误,今天)你先需要调用 gapi.load('auth2', callback)
并传递一个回调,然后调用 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
变量来实际登录用户。
虽然这些答案对我有帮助,但我相信官方文档中有更好的答案。
见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();
}
}
问题不仅在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
});
}
这对我有用:
包括这个脚本标签
<script src="https://apis.google.com/js/platform.js"></script>
对于 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>
便宜的修复是:
告诉 Eslint 这是一个全局变量,使用
/* global gapi */