Ошибка «Не удается установить заголовки после их отправки клиенту», полученная после попытки обслуживания нового файла html - PullRequest
0 голосов
/ 18 апреля 2020

Я очень новичок в NodeJS, и я пытаюсь следовать / строить пример проекта, созданного с помощью Spotify API и Express. Пользователю предлагается пройти аутентификацию на домашней странице, а затем я хочу, чтобы он попал в другой файл html, где соответствующая информация будет отображаться из API. Насколько я понимаю, "app.get" определяет, что должно произойти после перехода на эту конечную точку, поэтому я подумал, что когда мой клиентский файл. js получает '/ nextfile', я бы представил ему новый файл html для этого конечная точка с response.sendFile(__dirname + '/views/nextpage.html'); в пределах app.get('/nextpage').

Очевидно, это не правильно, потому что когда я запускаю сервер, он просто возвращается к индексу. html файл после аутентификации с ошибкой, которая гласит:

UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

Я попытался найти эту ошибку, но не смог найти ничего, что помогло бы мне решить мою конкретную проблему c. Соответствующие выдержки из моего клиента. js и сервера. js файлы приведены ниже:

Сервер. js

    /**  when home page is requested, respond with this file **/
app.get("/", function (request, response) {
  response.sendFile(__dirname + '/views/index.html');
});


//-------------------------------------------------------------//


// init Spotify API wrapper
var SpotifyWebApi = require('spotify-web-api-node');

// Replace with your redirect URI, required scopes, and show_dialog preference
var redirectUri = 'http://localhost:8888/callback',
    clID = '9013dc5d86b84ffca62df2f22e00968e',
    clSEC = 'b9484118ab374707925b1b15100cc58b';

var scopes = ['user-top-read','streaming','user-read-private'];
var showDialog = true;

// The API object we'll use to interact with the API
var spotifyApi = new SpotifyWebApi({
  clientId : clID,
  clientSecret : clSEC,
  redirectUri : redirectUri
});

app.get("/authorize", function (request, response) {
  var authorizeURL = spotifyApi.createAuthorizeURL(scopes, null, showDialog);
  console.log(authorizeURL)
  response.send(authorizeURL);
});

// Exchange Authorization Code for an Access Token
app.get("/callback", function (request, response) {
  var authorizationCode = request.query.code;

  spotifyApi.authorizationCodeGrant(authorizationCode)
  .then(function(data) {
    console.log(data)
    response.redirect(`/#access_token=${data.body['access_token']}&refresh_token=${data.body['refresh_token']}`)
  }, function(err) {
    console.log('Something went wrong when retrieving the access token!', err.message);
  });
});

app.get("/logout", function (request, response) {
  response.redirect('/'); 
});

    app.get('/nextpage', function (request, response) {
      **/* I want to serve his html file after the user is authenticated */**
      response.sendFile(__dirname + '/views/nextpage.html');

      var loggedInSpotifyApi = new SpotifyWebApi();
      console.log(request.headers['authorization'].split(' ')[1]);
      loggedInSpotifyApi.setAccessToken(request.headers['authorization'].split(' ')[1]);
      // do stuff with the api
    });

Клиент. js

$(function() {

    $('#login').click(function() {
      // Call the authorize endpoint, which will return an authorize URL, then redirect to that URL
      $.get('/authorize', function(data) {
        console.log(data)
        window.location = data;
      });
    });

    const hash = window.location.hash
      .substring(1)
      .split('&')
      .reduce(function (initial, item) {
        if (item) {
          var parts = item.split('=');
          initial[parts[0]] = decodeURIComponent(parts[1]);
        }
        return initial;
      }, {});
      window.location.hash = '';

    if (hash.access_token) {
      $.get({url: '/nextpage', headers: {"Authorization": `Bearer ${hash.access_token}`}}, function(data) {
        // "Data" is the array of track objects we get from the API. See server.js for the function that returns it.
        console.log(data)

        var title = $('<h3>Your top tracks on Spotify:</h3>');
        title.prependTo('#data-container-mod');

        // For each of the tracks, create an element
        data.items.forEach(function(track) {
          var trackDiv = $('<li class="track"></li>');
          trackDiv.text(track.name);
          trackDiv.appendTo('#data-container ol');
        });

      });
    }

  });

Любая помощь будет принята с благодарностью.

1 Ответ

0 голосов
/ 19 апреля 2020

Поток вашего приложения при отправке заголовков http выглядит примерно так, когда достигается URL «обратного вызова» по адресу: -

  1. Заголовок http отправляется вместе с URL-адресом перенаправления, который содержит токен доступа и refre sh токен.
  2. Клиент. js берет токен доступа и отправляет его обратно по маршруту / nextpage с заголовками, содержащими токен доступа
  3. Отправить следующую страницу. html обратно к клиенту. js и обновите страницу соответственно ..

Что будет дальше? Остерегайтесь, вкладка браузера все еще находится на маршруте с токенами доступа и refre sh токенами. Таким образом, запрос jquery ajax к / nextpage выполняется, когда предыдущие http-заголовки уже отправлены.

Однако я не понимаю, как возвращается индекс. html ..

Вы можете попробовать удалить window.location.hash = '' в клиенте. js

...