[英]Can not res.send() (error: "Cannot set headers after they are sent to the client") after I do query to database PostgrSQL
我知道,這聽起來很奇怪,但這是真的。 我正坐在 node.js 上制作 API,但是當我開始測試它時,我驚訝地發現幾乎在查詢處理開始時,當第一個 res.status().send() 到達時,VS 代碼掉落了一個“將標頭發送到客戶端后無法設置標頭”錯誤。
我如何意識到數據庫查詢是有罪的? 我使用“res.finished”屬性來檢查它何時“發送給客戶端”,並發現 res.finished 在數據庫查詢之后從“false”變為“true”。
誰知道它會是什么? 我已經用 MySQL 數據庫做了同樣的 API 事情,一切順利,但現在我使用的是 PostgreSQL,所以事情開始發生了。
我從 typescript 文件導出“PostgreSQL 管理器”class
PostgreSQL_Manager.ts:
module.exports = {
PostgreSQL_db_manager
}
在 index.ts 中導入並初始化:
index.ts
const PostgreSQL_mngr = require('./PostgreSQL_Manager.ts').PostgreSQL_db_manager;
const db = new PostgreSQL_mngr;
然后,如果我用查詢數據庫注釋語句,res.finished 保持假(我用 readRows (SELECT) 和 createRows(INSERT INTO) 試過):
Piece of index.ts code:
console.log('res.finished : ', res.finished);
//let nickval : any = await db.readRows('users', 'nickname', `nickname = \'${nickname}\'`);
//await db.createRows('test', '(color, odor, taste, quantity)', '(\'meaningless\', \'absent\', \'sadness\', 0)');
console.log('res.finished : ', res.finished);
Piece of Terminal:
res.finished : false
res.finished : false
但是當我取消注釋數據庫查詢時,它變成了這樣:
Piece of index.ts code:
console.log('res.finished : ', res.finished);
//let nickval : any = await db.readRows('users', 'nickname', `nickname = \'${nickname}\'`);
await db.createRows('test', '(color, odor, taste, quantity)', '(\'meaningless\', \'absent\', \'sadness\', 0)');
console.log('res.finished : ', res.finished);
Piece of Terminal:
res.finished : false
Postgres: Rows were created...
res.finished : true
postgres 管理器 class 中的 db.createRows 代碼如下所示:
public async createRows(table : string, columns: string | string[], values: string | string[]) : Promise<void> {
let createPromise = new Promise<void> ((resolve, reject) => {
this.db.query(`INSERT INTO ${table} ${columns} VALUES ${values};`, (err) => {
if(err) throw err;
console.log('Postgres: Rows were created...');
resolve();
});
});
await createPromise;
}
編輯 1:發生錯誤(此 function 從 app.post 調用,昵稱,email 和密碼具有字符串值):
async function validationUsers (res : any, email : string = undefined, password : string = undefined, nickname : string = undefined) : Promise<boolean> {
console.log('f:validationUsers email : ', email);
console.log('f:validationUsers password : ', password);
console.log('f:validationUsers : nickname', nickname);
//validation: nickname and email
if(nickname) {
console.log('res.finished : ', res.finished);
//let nickval : any = await db.readRows('users', 'nickname', `nickname = \'${nickname}\'`);
await db.createRows('test', '(color, odor, taste, quantity)', '(\'meaningless\', \'absent\', \'sadness\', 0)');
console.log('res.finished : ', res.finished);
/* if(nickval[0] !== undefined) {
console.log('frofkofro');
res.status(410).send('Nickname already exists');
res.end();
return false;
} */
}
//validation: email
if(email) {
let emailval : any = await db.readRows('users', 'email', `email = \'${email}\'`);
console.log('f:validationUsers if(email) emailval[0] : ', emailval[0]);
if(emailval[0] !== undefined) {
console.log("?00");
res.send('Email already exists');
res.end();
return false;
}
}
//validation: password
if(password) {
let passwordval = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,100}$/;
if(!password.match(passwordval)) {
console.log('password BAM!!!');
res.status(412).send('Password does not match the criteria'); <-- **THIS STRING**
console.log('password BOOM!!!');
//res.end();
return false;
}
}
console.log('End of f:validationUsers');
return true;
}
編輯 2:從 PostgreSQL 的“pg”庫到數據庫的 pool.query 或池連接是否有問題? 或者可能是 ts-node 編譯器的問題?
所以,我真的不明白這是怎么回事。 我不知道它是否重要,但我使用 ts-node 進行編譯和渲染 typescript
編輯 3:好的,所以我開始使用具有相同 5000 端口的新 ts 文件新服務器並運行以下命令:
app1.get('/db', async (req : any, res : any) => {
console.log('res.finished : ', res.finished);
await db1.createRows('test', '(color, odor, taste, quantity)', '(\'meaningless\', \'absent\', \'sadness\', 0)');
console.log('res.finished : ', res.finished);
res.status(200).send('All is fine this is send');
res.end();
});
並在控制台中產生:
Connected to database as pool successfully...
Server started on port 5000
res.finished : false
Postgres: Rows were created...
res.finished : false
而 POSTMAN 收到了 res.send()。 卧槽?????
當您的 PostgreSQL 代碼使用res.send()
發送多個結果時,會發生錯誤“標頭已發送...”。
我假設res.send()
部分在 PostgreSQL 管理器中,它看起來像一個經過測試的真實庫 - 那么是什么讓它向一個查詢發送兩個答案呢?
我沒有使用 Typescript 和 pSQL 的經驗,但我使用過 pSQL,並且記得幾年前遇到過同樣的問題。
PostgreSQL 支持(我想它仍然支持)多種查詢模式,例如UPDATE b SET a=2 WHERE c; SELECT a FROM b
UPDATE b SET a=2 WHERE c; SELECT a FROM b
。 這是兩個陳述,也是某些漏洞利用甚至可以起作用的原因。
而且,就像它發生在我身上一次,即使第二個長度為零並且顯然甚至不是查詢,在您的代碼中
`INSERT INTO ${table} ${columns} VALUES ${values};`
您的 PostgreSQL 經理可能只是認為有兩個語句。
所以,嘗試刪除那個看似無害的';' 最后,看看它是否解決了問題。 我沒有使用你的庫,但對我來說,它做到了。
我會說錯誤來自這里:
res.send('Email already exists');
res.end();
事實上,如果你節點的文檔是這樣寫的:
res.end() function 用於結束響應過程。 這個方法實際上來自Node核心,具體是HTTP.ServerResponse的response.end()方法。 用於在沒有任何數據的情況下快速結束響應。
鑒於您已經回復了'Email already exists'
express.js,您會收到錯誤消息Cannot set headers after they are sent to the client
(這只是意味着您已經發送了回復)
我想只是刪除res.end();
會解決你的問題。
好吧,這真的很奇怪。 我有中間件 function app.use,它看起來像這樣:
app.use(async function (req : any, res : any, next : any) {
console.log(smthng);
get('header') stuff;
if (cond) {
// this is not executed because condition was false in all my situation
} else {
// this is executed in all cases of this thread
req.name = undefined;
next();
}
next()
})
如您所見,中間件 function 的末尾是 next()。 所以,我刪除了 JUST THIS NEXT AND:
Terminal:
res.finished : false
Postgres: Rows were read...
[]
res.finished : false
res.finished : false
Postgres: Rows were read...
[]
f:validationUsers if(email) emailval[0] : undefined
res.finished : false
password BAM!!!
password BOOM!!!
我不知道發生了什么,我認為這是在 db promise、中間件和 res.send() 之間的十字路口下的深海精神分裂症超流體流動
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.