javascript Spotify API对API/令牌授权的错误请求错误:400

6vl6ewon  于 2023-02-21  发布在  Java
关注(0)|答案(2)|浏览(176)

我正在尝试使用Spotify API文档页面上的客户端凭据流来授权spotify API请求。以下是我使用fetch API的javascript ES6格式的代码

const response = await fetch('https://accounts.spotify.com/api/token', {
    mode: 'no-cors',
    method: 'POST',
    headers: {
      'Authorization': 'Basic Yzg4OWYzMjM5MjI0NGM4MGIyMzIyOTI5ODQ2ZjZmZWQ6MmUzZTM2YTMzMTM5NDM1Mzk3NzM4ZDMxMTg4MzM0Mjc=',
      'Content-type': 'application/x-www-form-urlencoded'
      },
    body: 'grant_type=client_credentials'
});

控制台表示这是一个错误请求,并且没有返回任何JSON。
另一件真正让我困惑的事情是,当我使用POSTMAN发送带有这些头部和主体的请求时,它返回的正是我想要的(它工作)我看不出这与我正在做的有什么不同...?有人能帮忙吗?
这里也是在Javascript Jquery AJAX 中的postman代码,如果这有帮助的话:

var settings = {
  "async": true,
  "crossDomain": true,
  "url": "https://accounts.spotify.com/api/token",
  "method": "POST",
  "headers": {
    "Authorization": "Basic Yzg4OWYzMjM5MjI0NGM4MGIyMzIyOTI5ODQ2ZjZmZWQ6MmUzZTM2YTMzMTM5NDM1Mzk3NzM4ZDMxMTg4MzM0Mjc=",
    "Content-Type": "application/x-www-form-urlencoded",
    "Cache-Control": "no-cache",
    "Postman-Token": "2f93918d-2e8e-4fb0-a168-7e153dd83912"
  },
  "data": {
    "grant_type": "client_credentials"
  }
}  

$.ajax(settings).done(function (response) {
  console.log(response);
});

这是DevTools

中的请求

yquaqz18

yquaqz181#

那个特定的端点并不意味着要在客户端使用。你应该在某个服务器端脚本中使用它。
https://developer.spotify.com/documentation/general/guides/authorization-guide/#client-credentials-flow
客户端凭据流用于服务器到服务器身份验证
另一个暗示是它只在服务器端使用,因为它使用您的客户端秘密,正如它的名字所暗示的那样,它意味着要保密,让它在客户端上可见并不是很保密。
因此,您可以从该端点获得访问令牌,然后在客户端使用该令牌向其他API端点(如https://api.spotify.com/v1/tracks)发出请求
现在说说为什么它在你的呼叫中不起作用。它在postman中起作用是因为它忽略了CORS,并且它正确地发送了授权报头。但是在浏览器中,你把fetch()请求模式设置为no-cors。在这个模式下,只能发送某些报头,并且javascript不能读取返回的响应。
由于这个原因,你的请求没有发送授权头,因为它不是no-cors模式下允许的简单头之一。所以你的请求失败了。即使授权通过了,你也不可能按照no-cors规则读取响应。
因此,如果要继续使用客户端凭据流,您需要:
1.从浏览器向您自己的服务器发出请求。

fetch("http://myserver.com/getToken")

1.在服务器上,您可以从那里发出https://accounts.spotify.com/api/token请求,发送所有正确的信息,然后将返回的访问令牌发送回客户机

//this is assuming a nodejs server environment
var postQuery = 'grant_type=client_credentials ';
var request = require('request');
var express = require('express');
var app = express();
app.get('/getToken', function(req, res){
  request({
    url: "https://accounts.spotify.com/api/token",
    method: "POST",
    headers: {
      'Authorization': 'Basic YourBase64EncodedCredentials',
      'Content-Type': 'application/x-www-form-urlencoded',
      'Content-Length': postQuery.length
    },
    body: postQuery
  }, function (error, response, data){
    //send the access token back to client
    res.end(data);
  });    
});

1.在正常提取请求中使用该访问令牌来请求您需要使用的端点,因为这些端点设置有正确的CORS标头

fetch("http://myserver.com/getToken")
.then(token=>{
  //token will be the token returned from your own server side script
  //now we can make a new request to the tracks (or any other api)
  return fetch("https://api.spotify.com/v1/tracks",{
    headers:{
      'Authorization': `Bearer ${token}`
    }
  }).then(r=>r.json())
})
.then(data=>{
   //data will be the data returned from tracks api endpoint
 });
ijnw1ujt

ijnw1ujt2#

正如帕特里克已经提到的,客户端凭据用于服务器端脚本。
我在本地测试Spotify API调用,希望使用fetch,而不是像client credentials documentation那样使用request库,但发现比预期的要难。
此方法与文档类似,使用fetch而不是post.request,并具有类似的请求选项集。
主要区别在于在标头中添加了'Content-Type'选项,并将form对象属性替换为body字符串属性。

const client_id = require('./keys.js').client_id; // Your client id
const client_secret = require('./keys.js').client_secret; // Your secret

// get authorisation token from Spotify
async function getSpotifyToken() {
    const url = 'https://accounts.spotify.com/api/token';
    response = await fetch(url, {
        method: 'POST',
        headers: {
            'Authorization': 'Basic ' + (Buffer.from(client_id + ':' + client_secret).toString('base64')),
            'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: 'grant_type=client_credentials',
        json: true
    });
    if (response.ok) {
        const jsonResponse = await response.json();
        console.log(jsonResponse);
    } else {
        console.log(response.statusText);
        throw new Error(`Request failed! Status code: ${response.status} ${response.statusText}`);
    }
}

getSpotifyToken()

如果你从你的机器或者服务器发出请求,我想它会起作用,如果你从浏览器调用API,使用另一个authorisation flow可能是最简单的。
希望能有所帮助。

相关问题