我正在使用NodeJS开发MVC应用程序。当应用程序第一次加载时,将创建数据库对象(使用池)。
var pool = mysql.createPool({connectionLimit: 150, host: __host,
user: __user, password: __password,
database: __database})
module.exports = pool
收到请求后,将创建一个Controller对象,该对象将创建一个Model来执行操作。模型从池获取连接,执行操作,并将连接释放回池。
//router snippet
router.get('/post_data', function(req, res){
router.setRequestAndResponse(req, res)
var post_data = new Post_Data()
post_data.processDataFromGet(router)
})
//controller code snippet
Post_Data_Controller.prototype.processDataFromGet = function(router){
var controller_obj = this
var data_array = {}
var req = router.req, res = router.res
//retrieving data from request and passing to the data_array
controller_obj.model.create(data_array, function(result){
var xml = xmlbuilder.create("response")
if (result.code == "error"){
xml.e("code", "error")
xml.e("message", result.error_message)
}else if (result.code == "success"){
xml.e("code", "success")
}
controller_obj.sendResponse(router.res, xml, "xml")
})
}
Post_Data_Controller.prototype.sendResponse = function(res, response, type){
if (type == "json"){
res.set({"Content-Type": "application/json", "Content-Length": JSON.stringify(response).length})
res.send(response)
}else{ /* Default type is XML */
res.set({"Content-Type": "application/xml", "Content-Length": response.end({pretty: true}).length})
res.send(response.end({pretty: true}))
}
}
//Model snippet
Post_Data.prototype.create = function(data_array, callback){
/* data validation */
var fail = false, error_data = {}
if (fail) {callback({code: "fail", cause: error_data}); return;}
//the next 2 lines do not throw an error when uncommented
//callback({code: "fail", cause: "how's it going"});
//return;
__db_pool.getConnection(function(err, db_conn){
// the next two lines throw an error for two or more requests coming in at the same time
callback({code: "fail", cause: "how's it going"});
return;
if (err) { callback({code: "error", error_message: err}); return;}
callback({code: "fail", cause: "how's it going"});
return;
db_conn.query("sql command", [data_array],
function(err, result){
if (err){ callback({code: "error", error_message: err}); return;}
if (result && result.length > 0){ //affiliate and listing exist
data_array.listing_id = result[0].listings_id
var data = [data_to_insert]
db_conn.query("sql command here", data,
function(err, result){
db_conn.release()
if (err){ callback({code: "error", error_message: err}); return;}
if (result && result.affectedRows > 0) {
callback({code: "success", data: {data_to_be_returned}})
}else {callback({code: "error", error_message:"Error inserting data"}); return}
})
}else{
callback({code: "fail", cause: "error to send back"})}
})
})
}
这些请求是Web服务请求。 如果我发送一个GET请求,则不会发生错误;但是,当我发送两个或更多并发请求时,我收到此错误:
/project_path/node_modules/mysql/lib/protocol/Parser.js:82
throw err;
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (http.js:689:11)
at ServerResponse.res.set.res.header (/project_path/node_modules/express/lib/response.js:549:10)
我将罪魁祸首追溯到上面粘贴的模型代码中的特定行。似乎由于某种原因,一旦模型从池获得第二个请求的连接,它就会以某种方式干扰第一个请求。两个请求仍然将适当的数据插入数据库;但是,第二次和后续请求不能再发送响应而不再发送错误。
我使用GET,POST和PUT内容类型执行了请求;只有GET才会抛出错误。所有其他内容类型都不会抛出任何错误,即使有超过一千个并发请求。
这是GET请求的Web服务代码;除了内容类型更改和正文中放置的数据之外,其他内容类型也是如此。
for(var i=0; i less than 5; i++){
sendAsGet()
i++
}
function sendAsGet(){
try{
var data = "?data_to_be_sent"
var uri =url.parse("http://localhost:4000/post_data")
var options = {hostname: uri.hostname, port: uri.port, method: "GET",
path: uri.path + data, agent: false}
request = (uri.protocol == "https")? https : http
var req = request.request(options, function(res){
var result = ""
console.log("STATUS: " + res.statusCode)
console.log("HEADERS: " + JSON.stringify(res.headers))
res.setEncoding("utf8")
res.setTimeout(50, null)
res.on("data", function(chunk){
result += chunk
})
res.on("end", function(){
console.log(result)
})
})
req.end()
}catch(err){
console.log(err.message)
}
}
我想知道两件事:
答案 0 :(得分:1)
您看到错误的原因是您在路由器本身上放置了请求/响应实例。 不要这样做。路由器对象是一个"静态"对象,它不是每个请求的东西。所以目前这是正在发生的事情(按顺序):
请求#1进入并在req
设置res
/ router
并启动异步model.create()
。
同时,请求#2进入并覆盖req
上的res
/ router
并启动自己的异步model.create()
。
调用请求#1' model.create()
回调,将响应发送到请求#2的套接字。
请求#2' model.create()
回调被调用,它会尝试向刚刚刚刚回复的同一res
发送回复。尝试将标题写入已发送的响应然后会导致您看到的错误。