INVALID_CLIENT: ошибка URI неверного перенаправления при запуске приложения страниц GitHub. Использует Spotify API - PullRequest
0 голосов
/ 29 апреля 2018

Я развернул приложение 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;
...