#node.js #express #mongodb-query
Вопрос:
Я работаю над серверной частью узла, которая использует MongoDB в качестве своей базы данных. Когда я должен отправить свой токен JWT в заголовке ответа, я получаю сообщение об ошибке, что заголовки не могут быть установлены после их отправки клиенту. Вот мой почтовый запрос:
api.post("/account/create", async (req, res) => {
// Hash the password using bcrypt
const hashedPassword = await bcrypt.hash(req.body.password, 10);
// Store new login credentials
const user = {
username: req.body.username,
password: hashedPassword
};
// Create a new JWT token
const token = jwt.sign({ username: req.body.username }, secret);
// Search for a matching username from the database
await logincollection.findOne(user, (err, result) => {
// If username was not found, add the credentials to the database
if (result == null) {
// Insert the credentials to the login credentials collection
logincollection.insertOne(user, (err, result) => {
// If an error occurred, return code 404 to the client
if (err) {
res.status(404).send();
}
})
// Create personal collection for the user
userdb.createCollection(JSON.stringify(user.username), (err, result) => {
// If an error occurred, return code 404 to the client
if (err) {
res.status(404).send();
}
})
// Return code 200 (success)
res.status(200).send({ auth: true, token: token });
} else {
// If username was found, return code 400 to the client
res.status(400).send();
}
})
})
Когда я пытаюсь получить значение токена в другом запросе POST, он возвращает undefined
:
api.post("/account/login", async (req, res) => {
// User object
const user = {
username: req.body.username,
password: req.body.password
};
const token = req.headers["token"];
console.log(token);
// Get username as a string
const username = JSON.stringify(user.username);
// Get hashed password from the collection
const hashedPassword = await logincollection.findOne({ username: req.body.username });
console.log(hashedPassword);
// Search for matching login credentials
await logincollection.find(user, (err, result) => {
// If no token was given
if (!token) {
// Return code 401 to the client
res.status(401).send();
}
// Verify the given JWT token
jwt.verify(token, secret, (err, decoded) => {
// If verification failed
if (err) {
// Return code 500 to the client
res.status(500).send();
}
// Return code 200 and decoded token to the client
res.status(200).send(decoded);
})
// Use bcrypt to compare the passwords and authenticate login
bcrypt.compare(req.body.password, hashedPassword).then(match => {
// If the credentials match
if (match) {
// Return the result as an object
const sendObject = {
username: result.username,
password: result.password
};
// Return code 200 to the client
res.status(200).send(sendObject);
// Log to console when user logs in
console.log("User " username " logged in");
// If the credentials do not match
} else {
// Return code 404 to the client
res.status(404).send();
}
// If comparing fails
}).catch(error => {
// Return coe 500 to the client
res.status(500).send();
})
})
})
Я почти уверен, что решение-это что-то невероятно простое, но я просто не могу решить эту проблему, хотя я уже провел много исследований.
Вот ответ, возвращенный клиенту из запроса /учетная запись/создать:
{
"auth": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QyIiwiaWF0IjoxNjMzNzg3MjE2fQ.duo5R9wXpk2Gj-iPHFMaDgKK0p3h6WZf5vnXrZViePo"
}
ИЗМЕНИТЬ: Оказывается, что токен переходит не в заголовок, а в тело. Что мне нужно сделать по-другому, чтобы передать его в заголовок?
Комментарии:
1. вы уверены, что результат вызова API «/учетная запись/создать» со статусом 200 вернет токен правильно?
2. пожалуйста, поделитесь своими кодами на стороне клиента, которые связаны с установкой токена в заголовке. вы также можете проверить это на вкладке сеть chrome, проверив вызов API и проверив его заголовок. правильно ли прикреплен и отправлен токен с помощью вызовов API?
3. @novonimo Я внес некоторые изменения в вопрос, включая оставшуюся часть запроса на вход и ответ, данный запросом /учетная запись/создать
4. как я уже упоминал ранее, пожалуйста, добавьте связанный с клиентом код
5. @novonimo Что вы подразумеваете под кодом, связанным с клиентом? Интерфейс для этого-приложение для Android, вы имеете в виду этот код?
Ответ №1:
В этом result == null
случае у вас есть три инструкции, которые отправляют ответ: две асинхронные res.status(404)
инструкции и одна синхронная res.status(200)
инструкция. Только из них могут быть выполнены по запросу.
Но в текущем коде оператор status 200 выполняется для каждого запроса, даже если неудачная операция с базой данных позже приводит к дополнительному оператору status 404, который затем вызывает наблюдаемую ошибку.
Комментарии:
1. Я изменил код так, чтобы код ответа 200 возвращался только после успешного завершения всех операций с базой данных, но конечный результат тот же.
Ответ №2:
Ладно, похоже, я понял это неправильно.
Я думал, что токен всегда должен быть возвращен и получен в заголовке. Это не тот случай. Ответ токена от /учетная запись/создать должен быть в теле. Токен должен быть установлен только в заголовок при запуске запроса /учетная запись/вход (аутентификация входа).
Надеюсь, это может помочь кому-то, у кого в будущем возникнет тот же вопрос.