错误[ERR_HTTP_HEADERS_SENT]:在将标头发送到客户端后,第二次按下按钮时,无法设置标头



我目前正在学习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服务器的代码:

颤振:按下按钮调用函数:

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);
});
});

我将感谢任何帮助!

当你依赖事件,但你没有将这些事件与特定的请求联系起来时,你会有一段糟糕的时间:现在,请求映射到"什么都没有";,但随后代码继续将触发响应的事件绑定到您曾经声明过的每个app.on("response", ...)绑定。。。在这个过程中,还可以防止响应被垃圾收集,因为它们需要一直呆在那里进行事件处理。因此,您的代码实际上也存在内存泄漏。

使用promise/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 };

最新更新