【发布时间】:2019-02-15 12:58:48
【问题描述】:
我创建了一个仅适用于 Spotify 高级用户的应用(根据 Spotify 的文档,PUT 方法不适用于非高级用户)。这是一个包含十个问题的交互式测验,播放列表会在您的 Spotify 帐户中生成,播放后您必须猜出每首歌曲的名称。它使用 NodeJS 后端生成并通过 ReactJS 显示。游戏可以在这里演示:https://am-spotify-quiz.herokuapp.com/
可以在下面查看代码:
server.js
const express = require('express');
const request = require('request');
const cors = require('cors');
const querystring = require('querystring');
const cookieParser = require('cookie-parser');
const client_id = ''; // Hiding for now
const client_secret = ''; // Hiding
const redirect_uri = 'https://am-spotify-quiz-api.herokuapp.com/callback/';
const appUrl = 'https://am-spotify-quiz.herokuapp.com/#';
/**
* Generates a random string containing numbers and letters
* @param {number} length The length of the string
* @return {string} The generated string
*/
var generateRandomString = function(length) {
var text = '';
var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (var i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
};
var stateKey = 'spotify_auth_state';
var app = express();
app.use(express.static(__dirname + '/public'))
.use(cors())
.use(cookieParser());
app.get('/login', function(req, res) {
var state = generateRandomString(16);
res.cookie(stateKey, state);
// scopes needed to make required functions work
var scope = 'user-read-private ' +
'user-read-email ' +
'user-read-playback-state ' +
'user-top-read ' +
'playlist-modify-public ' +
'playlist-modify-private ' +
'user-modify-playback-state ' +
'user-read-playback-state';
res.redirect('https://accounts.spotify.com/authorize?' +
querystring.stringify({
response_type: 'code',
client_id: client_id,
scope: scope,
redirect_uri: redirect_uri,
state: state
}));
});
app.get('/callback/', function(req, res) {
// your application requests refresh and access tokens
// after checking the state parameter
var code = req.query.code || null;
var state = req.query.state || null;
var storedState = req.cookies ? req.cookies[stateKey] : null;
if (state === null || state !== storedState) {
res.redirect(appUrl +
querystring.stringify({
access_token: access_token,
refresh_token: refresh_token
}));
} else {
res.clearCookie(stateKey);
var authOptions = {
url: 'https://accounts.spotify.com/api/token',
form: {
code: code,
redirect_uri: redirect_uri,
grant_type: 'authorization_code'
},
headers: {
'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64')),
},
json: true
};
request.post(authOptions, function(error, response, body) {
if (!error && response.statusCode === 200) {
var access_token = body.access_token,
refresh_token = body.refresh_token;
var options = {
url: 'https://api.spotify.com/v1/me',
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type': 'application/json' // May not need
},
body: { // Likely don't need this anymore!
'name': 'Test Playlist',
'public': false
},
json: true
};
// use the access token to access the Spotify Web API
request.get(options, function(error, response, body) {
console.log(body);
});
// we can also pass the token to the browser to make requests from there
res.redirect(appUrl +
querystring.stringify({
access_token: access_token,
refresh_token: refresh_token
}));
} else {
res.redirect(appUrl +
querystring.stringify({
error: 'invalid_token'
}));
}
});
}
});
// AM - May not even need this anymore!
app.get('/refresh_token', function(req, res) {
// requesting access token from refresh token
var refresh_token = req.query.refresh_token;
var authOptions = {
url: 'https://accounts.spotify.com/api/token',
headers: { 'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64')) },
form: {
grant_type: 'refresh_token',
refresh_token: refresh_token
},
json: true
};
request.post(authOptions, function(error, response, body) {
if (!error && response.statusCode === 200) {
var access_token = body.access_token;
res.send({
'access_token': access_token
});
}
});
});
console.log('Listening on 8888');
app.listen(process.env.PORT || 8888);
我有一个 react 组件,它会在用户登录后立即显示,名为 premium.js。如果你需要所有的代码,你可以看到它here。以下是我的游戏需要的两种 PUT 方法;一个用于关闭随机播放功能,另一个用于播放播放列表:
removeShuffle() {
axios({
url: 'https://api.spotify.com/v1/me/player/shuffle?state=false',
method: "PUT",
headers: {
'Authorization': 'Bearer ' + this.state.accesstoken
}
})
.then((response) => {
console.log(response)
})
.catch((error) => {
console.log(error)
})
}
// Then... play the playlist to get started
playPlaylist(contextUri) {
axios({
url: 'https://api.spotify.com/v1/me/player/play',
method: "PUT",
data: {
context_uri: contextUri
},
headers: {
'Authorization': 'Bearer ' + this.state.accesstoken
}
})
.then((response) => {
console.log(response)
})
.catch((error) => {
console.log(error)
})
}
当我作为游戏的创造者尝试时,这些都可以正常工作;但是,我让另一个高级用户尝试了它并发现了这个错误:
这似乎没有多大意义,因为我发现此错误发生在其他用户身上,无论他们使用的是 Windows 还是 Mac。有谁知道这意味着什么,我该如何解决?提前致谢!
【问题讨论】: