我正在尝试使用 Spotify 的 Web API 为我的仅前端单页应用程序获取当前用户的播放列表,但控制台在尝试获取访问令牌时给我一个 400 错误,我认为这是一个语法错误代码。我正在使用 Spotify 的 PKCE 授权指南,但我不确定自己做错了什么。我可以毫无问题地访问 Spotify 的登录页面,但无法检索访问令牌。我确实注意到 VS Code 说 btoa(在 generateCodeChallenge 函数中使用)已被弃用,但我不确定在它的位置还可以使用什么。此外,当我尝试 console.log codeVerifier 变量时,它只记录 null(我认为这可能是由于 btoa 被弃用)。我认为这就是问题所在,但我不确定如何解决它。
这是我目前写的代码(我去掉了clientId和redirectUri):
const clientId =
const redirectUri =
function generateRandomString(length) {
let text = '';
let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
async function generateCodeChallenge(codeVerifier) {
function base64encode(string) {
return btoa(String.fromCharCode.apply(null, new Uint8Array(string)))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
}
const encoder = new TextEncoder();
const data = encoder.encode(codeVerifier);
const digest = await window.crypto.subtle.digest('SHA-256', data);
return base64encode(digest);
}
const Spotify = {
login() {
let codeVerifier = generateRandomString(128);
generateCodeChallenge(codeVerifier).then(codeChallenge => {
let state = generateRandomString(16);
let scope = 'user-read-private user-read-email';
localStorage.setItem('code-verifier', codeVerifier);
let args = new URLSearchParams({
response_type: 'code',
client_id: clientId,
scope: scope,
redirect_uri: redirectUri,
state: state,
code_challenge_method: 'S256',
code_challenge: codeChallenge
});
window.location = 'https://accounts.spotify.com/authorize?' + args;
})
},
getAccessToken() {
const urlParams = new URLSearchParams(window.location.search);
let code = urlParams.get('code');
let codeVerifier = localStorage.getItem('code_verifier');
let body = new URLSearchParams({
grant_type: 'authorization_code',
code: code,
redirect_uri: redirectUri,
client_id: clientId,
code_verifier: codeVerifier
});
fetch('https://accounts.spotify.com/api/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: body
})
.then(response => {
if (!response.ok) {
throw new Error('HTTP status ' + response.status);
}
return response.json();
})
.then(data => {
localStorage.setItem('access-token', data.access_token);
})
.catch(error => {
console.error('Error:', error);
});
},
async getPlaylists() {
let accessToken = localStorage.getItem('access_token');
const headers = {Authorization: 'Bearer ' + accessToken};
const response = await fetch('https://api.spotify.com/v1/me/playlists?limit=20&offset=0', {headers: headers});
const data = await response.json();
const playlists = data.items;
return playlists;
}
}
export default Spotify;