#node.js #express #flutter #dart
#node.js #экспресс #трепетание #dart
Вопрос:
В настоящее время я изучаю Flutter / DART и пытаюсь создать приложение, которое взаимодействует с сервером, но у меня проблемы. Есть кнопка входа, которая отправляет запрос на сервер, сервер проверяет, есть ли пользователь с этим именем пользователя и паролем, и ответ отправляется обратно. При первом нажатии кнопки все работает нормально, но при повторном нажатии кнопки и т. Д. На сервере появляются всплывающие окна с ошибкой:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:526:11)
at ServerResponse.header (C:UsersPCDesktopFlutter Node.js Login-Register Appservernode_modulesexpresslibresponse.js:771:10)
at ServerResponse.send (C:UsersPCDesktopFlutter Node.js Login-Register Appservernode_modulesexpresslibresponse.js:170:12)
at ServerResponse.json (C:UsersPCDesktopFlutter Node.js Login-Register Appservernode_modulesexpresslibresponse.js:267:15)
at ServerResponse.send (C:UsersPCDesktopFlutter Node.js Login-Register Appservernode_modulesexpresslibresponse.js:158:21)
at Function.<anonymous> (C:UsersPCDesktopFlutter Node.js Login-Register Appserverserver.js:14:39)
at Function.emit (events.js:326:22)
at Query.<anonymous> (C:UsersPCDesktopFlutter Node.js Login-Register Appserverdb.js:17:20)
at Query.<anonymous> (C:UsersPCDesktopFlutter Node.js Login-Register Appservernode_modulesmysqllibConnection.js:526:10)
at Query._callback (C:UsersPCDesktopFlutter Node.js Login-Register Appservernode_modulesmysqllibConnection.js:488:16) {
code: 'ERR_HTTP_HEADERS_SENT'
}
Вот код из приложения flutter и из node.js сервер:
Flutter: функция вызывается при нажатии кнопки:
void signIn(username, password) async {
final bodyEncoded = jsonEncode(
{
'username': model.username,
'password': model.password,
},
);
final response = await http.post(
'http://192.168.0.110:3000/signin',
headers: {'Content-Type': 'application/json'},
body: bodyEncoded,
);
if (response.body == 'true')
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MainBody(),
),
);
else
setState(() => {elementOpacity = 1.0});
}
Сервер
server.js
const express = require('express');
const app = express();
const server = require('./server.json');
exports.app = app;
const db = require('./db');
app.use(express.json());
app.post('/signin', (req, res) => {
const {username, password} = req.body;
app.emit('signInRequest', username, password);
app.on('response', (value) => res.send(value));
});
app.listen(server.port, () => console.log('Server running on port ' server.port));
db.js
const mysql = require('mysql');
const connectionUri = require('./db.json');
const db = mysql.createConnection(connectionUri);
const app = require('./server').app;
db.connect((err) => {
if (err)
throw err;
console.log('MySQL connection successful!');
});
app.on('signInRequest', (username, password) => {
db.query("SELECT Count(*) AS 'count' FROM Users WHERE (Username = '" username "' AND Password = '" password "')", (err, result) => {
if(err)
throw err;
return app.emit('response', result[0].count == 1 ? true : false);
});
});
Я буду признателен за любую помощь!
Комментарии:
1. Ответьте как ответ, но как прямой комментарий к вашему коду: никогда, никогда не пишите запросы к базе данных таким образом. xkcd.com/327 это смешно, потому что это правда, так что читайте npmjs.com/package/mysql#preparing-queries и примените это на практике.
2. Спасибо, сэр, за ваш ответ, я очень благодарен!
Ответ №1:
Когда вы полагаетесь на события, но не привязываете эти события к конкретному запросу, у вас будут плохие времена: прямо сейчас запросы сопоставляются с «ничем», но затем код продолжает привязывать событие, которое вызывает ответ на каждую app.on("response", ...)
привязку, которую вы когда-либо объявляли … и впроцесс, также предотвращающий сбор мусора в ответах, потому что им постоянно нужно оставаться для обработки событий. Таким образом, ваш код также имеет то, что фактически является утечкой памяти.
Вместо того, чтобы делать это с событиями, используйте обещания / async
функции, а затем await
их возвращаемое значение. Таким образом, один запрос сопоставляется с одним ответом, и все также очищается должным образом.
server.js
const express = require('express');
const app = express();
const database = require('./database.js');
const server = require('./server.json');
exports.app = app;
app.use(express.json());
app.post('/signin', async (req, res, next) => {
const { username, password } = req.body;
if (!validateUsernameAndPassword(username, password)) {
// Remember to write a global error handler. Or don't use
// Express' next(err) functionality but respond with a call-appropriate
// response that has the correct HTTP error code, too.
next(new Error("you better believe this should be an error"));
}
const value = await database.handleSignInRequest(username, password);
res.send(value);
});
app.listen(server.port, () => console.log('Server running on port ' server.port));
database.js:
const mysql = require('mysql');
const connectionUri = require('./db.json');
const db = mysql.createConnection(connectionUri);
// the db code shouldn't have to know anything about express or express apps
db.connect((err) => {
if (err)
throw err;
console.log('MySQL connection successful!');
});
function handleSignInRequest(username, password) {
return new Promise((resolve, reject) => {
// Now, a super important note: NEVER QUERY A DATABASE DIRECTLY LIKE THIS:
db.query(`SELECT Count(*) AS 'count' FROM Users WHERE (Username = '${username}' AND Password = '${password}')`, (err, result) => {
if(err) return reject(err);
resolve(result[0].count == 1 ? true : false);
});
// Look up how to query your database in a sanitized, prepared statement
// fashion. https://xkcd.com/327/ is a word famous piece of satire for
// good reason.
//
// Please read https://www.npmjs.com/package/mysql#preparing-queries and
// put that into practice.
});
});
module.exports = { handleSignInRequest };