Я новичок в Koa.js и пытаюсь создать простой процесс аутентификации с помощью Spotify. Вот мой код:
import koa from "koa";
import querystring from "node:querystring";
const port = 54832;
const client_id = "myClientID";
const redirect_uri = `http://localhost:${port}/callback`;
const scope = "user-read-currently-playing";
export default function requestAuth() {
const server = new koa();
let response = {};
server.use(async (ctx) => {
const { url, method } = ctx.request;
if (method === "GET" && url === "/login") {
ctx.body = "You will be redirected to Spotify auth page";
ctx.redirect(
"https://accounts.spotify.com/authorize?" +
querystring.stringify({
response_type: "code",
client_id: client_id,
scope: scope,
redirect_uri: redirect_uri,
})
);
} else if (method === "GET" && url.includes("/callback")) {
if (!ctx.request.query.error) {
response.code = ctx.request.query.code;
} else {
console.info(ctx.request.query.error);
}
}
});
server.listen(port);
return response;
}
Я хочу перенаправлять пользователей на страницу входа в Spotify, когда они посещают URL-адрес /login
. Однако вместо перенаправления на Spotify меня перенаправляют на локальный URL-адрес http://localhost:54832/response_type=code&client_id=myClientID&redirect_uri=http%3A%2F%2Flocalhost%3A54832&scope=user-read-currently-playing
и я получаю сообщение «Не найден» в теле ответа.
Я делаю что-то не так с тем, как обрабатываю перенаправление? Может ли это быть проблема с настройкой моего сервера или с тем, как Koa.js обрабатывает перенаправления? Любые предложения о том, как устранить неполадку или исправить это?
Чуть раньше у меня была такая же проблема с Express JS. Как я тогда понял, проблема была в кешировании, которое в этом фреймворке сложно отключить. Именно поэтому я перешёл на Koa JS. Но поскольку проблема сохраняется и в этом случае, я в полной растерянности
Функция requestAuth()
возвращает объект немедленно, до обработки HTTP-запросов, поэтому он всегда пуст и бесполезен.
Вот как вы можете реорганизовать код, чтобы он работал более эффективно, придерживаясь типичного использования Koa для обработки нескольких асинхронных запросов.
Сохранить как demo.js
import Koa from 'koa'
import Router from 'koa-router'
import bodyParser from 'koa-bodyparser'
import cors from '@koa/cors'
import axios from 'axios'
import querystring from "querystring";
const app = new Koa()
const router = new Router()
const CLIENT_ID = "{your client id}";
const CLIENT_SECRET = "{your client secret}";
const PORT = 3000; // replace your port
const REDIRECT_URI = `http://localhost:${PORT}/callback`
const SCOPE = 'user-read-currently-playing'
app.use(cors());
app.use(bodyParser());
const getToken = async (code) => {
try {
const response = await axios.post('https://accounts.spotify.com/api/token',
querystring.stringify({
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': REDIRECT_URI
}),
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
auth: {
username: CLIENT_ID,
password: CLIENT_SECRET
}
});
return response.data.access_token
} catch (err) {
console.error(err)
throw err
}
}
router.get('/login', async (ctx) => {
const redirect_url = `https://accounts.spotify.com/authorize?${
querystring.stringify({
response_type: 'code',
client_id: CLIENT_ID,
scope: SCOPE,
state: '123456',
redirect_uri: REDIRECT_URI,
prompt: 'consent'
})}`
await ctx.redirect(redirect_url)
})
router.get('/callback', async (ctx) => {
const code = ctx.query.code;
try {
const access_token = await getToken(code);
ctx.body = { 'access_token': access_token };
} catch (error) {
console.error(error.message)
ctx.status = 500
ctx.body = { error: 'Failed to retrieve access token' }
}
})
app.use(router.routes()).use(router.allowedMethods())
app.listen(PORT, () => {
console.info(`Listening on http://localhost:${PORT}`)
})
npm install koa koa-router koa-bodyparser @koa/cors axios querystring
package.json
{
"type": "module",
"dependencies": {
"@koa/cors": "^5.0.0",
"axios": "^1.6.8",
"cors": "^2.8.5",
"koa": "^2.15.3",
"koa-bodyparser": "^4.4.1",
"koa-router": "^12.0.1",
"querystring": "^0.2.1"
}
}
node demo.js
http://localhost:3000/login
Замените 3000 на номер порта.
Почему ваше промежуточное ПО не является асинхронным в первом блоке router.get(), но есть во втором?
Хорошо, что вы можете сделать это асинхронно (ctx). .. жду ctx', как и другие
URLSearchParams и строка запроса – это одна и та же функция.
@ghostone, обновите код, используя querystring
и шаблон async/await. Это тоже работает. Можете ли вы принять мой ответ?
@ghostone, спасибо, что согласился, можешь тоже отказаться от голосования?
Хороший ответ, спасибо. Почему вы использовали URLSearchParams вместо строки запроса?