Я развернул приложение React на страницах GitHub, которое использует API Spotify, чтобы получить текущий воспроизводимый трек на Spotify и отобразить его на веб-странице. Он отлично работает локально и использует локальный сервер, работающий на порту 8888, для отправки запросов API и перенаправления в приложение, работающее на localhost: 3000. Проблема заключается в том, что приложение как есть выдает вышеуказанную ошибку, когда я пытаюсь запросить токен из API Spotify, и я предполагаю, что это потому, что используемый мной URI перенаправления больше не действителен, так как приложение теперь находится на GitHub и не может связаться с localhost: 3000.
Ниже приведен код, который работал на localhost: 8888 и получил токен доступа. Я изменил свой URI перенаправления, чтобы он соответствовал расположению размещенной версии приложения.
var express = require('express'); // Express web server framework
var request = require('request'); // "Request" library
var querystring = require('querystring');
var cookieParser = require('cookie-parser');
var client_id = '[MY_CLIENT_ID]'; // Your client id
var client_secret = '[MY_CLIENT_SECRET]'; // Your secret
var redirect_uri = 'http://malcolmross19.github.io/project/'; // Your redirect uri
/**
* 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(cookieParser());
app.get('/login', function(req, res) {
var state = generateRandomString(16);
res.cookie(stateKey, state);
// your application requests authorization
var scope = 'user-read-private user-read-email 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('/#' +
querystring.stringify({
error: 'state_mismatch'
}));
} 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 },
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('http://malcolmross19.github.io/project/#' +
querystring.stringify({
access_token: access_token,
refresh_token: refresh_token
}));
} else {
res.redirect('/#' +
querystring.stringify({
error: 'invalid_token'
}));
}
});
}
});
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(8888);
Ниже приведен код самого приложения. Я уверен, что мне нужно изменить атрибут href в ссылке, чтобы перейти куда-то, кроме localhost: 8888, но я точно не знаю, где именно.
import React, { Component } from 'react';
import './App.css';
import SpotifyWebApi from 'spotify-web-api-js';
import ReactCountdownClock from 'react-countdown-clock';
const spotifyApi = new SpotifyWebApi();
class App extends Component {
constructor(){
super();
const params = this.getHashParams();
const token = params.access_token;
if (token) {
spotifyApi.setAccessToken(token);
}
this.state = {
loggedIn: token ? true : false,
nowPlaying: { name: 'Not Checked', albumArt: ''},
currentCount: 5,
clockHidden: true,
songInfoHidden: true,
answer: ''
}
this.getNowPlaying = this.getNowPlaying.bind(this);
this.getHashParams = this.getHashParams.bind(this);
this.toggleClock = this.toggleClock.bind(this);
this.toggleInfo = this.toggleInfo.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
getNowPlaying(){
spotifyApi.getMyCurrentPlaybackState()
.then((response) => {
console.log(response)
this.setState({
nowPlaying: {
name: response.item.name,
albumArt: response.item.album.images[0].url
}
});
})
}
getHashParams(){
var hashParams = {};
var e, r = /([^&;=]+)=?([^&;]*)/g,
q = window.location.hash.substring(1);
e = r.exec(q)
while (e) {
hashParams[e[1]] = decodeURIComponent(e[2]);
e = r.exec(q);
}
return hashParams;
}
toggleClock(){
this.setState({
clockHidden: !this.state.clockHidden
});
}
toggleInfo(){
this.toggleClock();
this.setState({
songInfoHidden: !this.state.songInfoHidden,
});
}
buttonClick(e){
this.getNowPlaying();
if(this.state.songInfoHidden){
this.toggleClock();
} else {
this.toggleInfo();
this.setState({
answer: ''
});
}
}
handleChange(event){
this.setState({
answer: event.target.value
});
}
handleSubmit(event){
event.preventDefault();
this.toggleInfo();
}
render() {
return (
<div className="App">
<div className="MainHeader">
{!this.state.loggedIn &&
<div>
<h1>Login to Spotify to use Name That Tune</h1>
</div>}
{this.state.loggedIn &&
<div>
<h1>Name That Tune</h1>
</div>}
<a href="http://localhost:8888">Request Access From Spotify</a>
</div>
<div className="Body">
<hr />
{this.state.loggedIn && !this.state.clockHidden &&
<ReactCountdownClock
seconds={30}
color='#5CC8FF'
alpha={0.9}
size={720}
onComplete={() => this.toggleInfo()}
/>}
{this.state.loggedIn && !this.state.songInfoHidden &&
<div>
<h1 className="Header">How Did You Do?</h1>
<div className="NowPlaying">Now Playing: { this.state.nowPlaying.name }</div>
</div>}
<br />
{this.state.loggedIn && !this.state.songInfoHidden &&
<div>
<img src={this.state.nowPlaying.albumArt} style={{ height: 650 }}/>
</div>}
{this.state.loggedIn && !this.state.clockHidden &&
<form onSubmit={this.handleSubmit}>
<label>
<input type="text" value={this.state.answer} placeholder="Enter Your Answer Here" onChange={this.handleChange} />
</label>
<input type="submit" value="Check Answer" />
</form>}
<br />
{this.state.loggedIn && !this.state.songInfoHidden &&
<div>
<h1>Your Answer:<br /></h1>
<div className="Answer">{this.state.answer}</div>
</div>}
<br />
{this.state.loggedIn &&
<button className="NowPlayingButton" onClick={() => this.buttonClick()}>
Check Now Playing
</button>
}
</div>
</div>
);
}
}
export default App;