Error: Can't set headers after they are sent
发布于 7 年前 作者 newonejoe 6131 次浏览 来自 问答

新手一名,遇到问题,困扰了一天了,帮忙看看是什么问题啊 直接上code html:

<table class="ui selectable celled table segment" id="tbEventMessage">
      <thead>
        <tr>
          <th>Event ID</th>
          <th>Precursor Id</th>
          <th>DataItem Id</th>
          <th>Zone Number</th>
          <th>Condition Id</th>
          <th>SubCondition Id</th>
          <th>State</th>
          <th>Active Time</th>
          <th>Event Time</th>
          <th>Severity</th>
          <th>Threshold</th>
          <th>Message</th>
        </tr>
      </thead>
      <tbody>
      </tbody>
      <tfoot class="full-witdh">
        <tr>
          <th colspan="3">
            <a class="ui right labeled icon button" href="/eventMessages/create">
              <i class="user icon"></i>Add eventMessage 
            </a>  
          </th>
        </tr>
      </tfoot>
    </table>

Javascript:

		 var messageTable = $('#tbEventMessage').DataTable({
			ajax:{
				url: "/eventMessages",
				type: "get",
				dataSrc: ""
			},
			columns : [
				{data: 'EventID'},
				{data: 'PrecursorId'},
				{data: 'DataItemId'},
				{data: 'ZoneNumber'},
				{data: 'ConditionId'},
				{data: 'SubConditionId'},
				{data: 'State'},
				{data: 'ActiveTime', render: function(data){
					return data.replace(/T/, ' ').replace(/\..+/, ''); 
					}
				},
				{data: 'EventTime', render: function(data){
					return data.replace(/T/, ' ').replace(/\..+/, ''); 
					}
				},
				{data: 'Severity'},
				{data: 'Threshold'},
				{data: 'Message'}
			],
			createdRow: function(row, data, index) {
				var severity = data['Severity'];
				if (severity >= 700) {
					$('td',row).css('background-color', "crimson");
				}else if(severity >= 400){
					$('td',row).css('background-color', "#FA8072");
				}else if (severity >= 100){
					$('td',row).css('background-color', "coral");
				}else{
					$('td',row).css('background-color', "#4FC08D");						
				}
			}
		});
		
		setTimeout(refresh, 1000);
		
		function refresh() {
			//ajax
			messageTable.ajax.reload();
			setTimeout(refresh, 1000);
		}

model:

const sql = require('mssql');
var config = {
    user: 'sa',
    password: 'porta',
    server: 'CN10LT099',
    database: 'ClairAlarm',
    pool: {
	    max: 10,
	    min: 0,
	    idleTimeoutMillis: 30000
    }
};


module.exports = {
    closeConnection: function closeConnection() {
	    sql.close();
    },
    getEventMessages: function getEventMessages(limit) {
	    //console.log(limit);
	    return new sql.ConnectionPool(config).connect().then(pool => {
		  // Query
		    return pool.request()
		    .input('recordlimit', sql.Int, parseInt(limit))
		    .execute('ReadEventMessage')
		    }).then(result => {
			//pool.close();
			    return result.recordset;
		    }).catch(err => {
			    //pool.close();
			    console.trace(err);
		   });
	 }    
};

eventMessages.js

var express = require('express');
var router = express.Router();
var EventMessageModel = require('../models/eventMessages');
var checkLogin =  require('../middlewares/check.js').checkLogin;
// GET /eventMessages
router.get('/', function(req, res, next) {
EventMessageModel.getEventMessages(20)
    .then(function(eventMessages) {
    	//console.dir(eventMessages);
        //res.end(JSON.stringify(eventMessages));
        res.json(eventMessages);
     });
    //.catch(next);
});
module.exports =  router;
13 回复

@2VCl1md 谢谢,我知道是这个相关的问题,就是找不到哪里错了啊,我这边用的是res.json(), 这个有问题吗?

@newonejoe 应该是吧,我之前也遇到过这个问题

我的问题好像和同一个页面的两个ajax有关系, 两个ajax会有冲突吗?我真的是个小白,帮我看看吧 7-13-2017 5-29-31 PM.bmp

<script type="text/javascript">
// 使通知框延时自动从页面删除
$(document).ready( function () {
  // 延时清除掉成功、失败提示信息
  if ($('.ui.success.message').length > 0) {
    $('.ui.success.message').fadeOut(1000)
  } else if ($('.ui.error.message').length > 0) {
    $('.ui.error.message').fadeOut(1000)
  }
  
  // 鼠标悬浮在头像上,弹出气泡提示框
  $('.post-content .avatar-link').popup({
    inline: true,
    position: 'bottom right',
    lastResort: 'bottom right'
  });

  // datatable
  //$('.ui.table').DataTable();
		//var table = $('.ui.table').DataTable({
		//	ajax: '/data/arrays.txt'
		//});
		
		$('.ui.accordion').accordion();
		//var messageTable = $('#tbEventMessage').DataTable();
		var messageTable = $('#tbEventMessage').DataTable({
			ajax:{
				url: "/eventMessages",
				//type: "get",
				async: false,
				dataSrc: ""
			},
			columns : [
				{data: 'EventID'},
				{data: 'PrecursorId'},
				{data: 'DataItemId'},
				{data: 'ZoneNumber'},
				{data: 'ConditionId'},
				{data: 'SubConditionId'},
				{data: 'State'},
				{data: 'ActiveTime', render: function(data){
					return data.replace(/T/, ' ').replace(/\..+/, ''); 
					}
				},
				{data: 'EventTime', render: function(data){
					return data.replace(/T/, ' ').replace(/\..+/, ''); 
					}
				},
				{data: 'Severity'},
				{data: 'Threshold'},
				{data: 'Message'}
			],
			createdRow: function(row, data, index) {
				var severity = data['Severity'];
				if (severity >= 700) {
					$('td',row).css('background-color', "crimson");
				}else if(severity >= 400){
					$('td',row).css('background-color', "#FA8072");
				}else if (severity >= 100){
					$('td',row).css('background-color', "coral");
				}else{
					$('td',row).css('background-color', "#4FC08D");						
				}
			}
		});
		
		/*
		setTimeout(refresh, 1000);
		
		function refresh() {
			//ajax
			messageTable.ajax.reload();
			setTimeout(refresh, 1000);
		}
		*/
		

  // side bar
  //$('#menu').click(function() {
  //    $('.ui.sidebar').sidebar('toggle');        
  //});

  //
  $('.ui.sidebar').first()
      .sidebar('attach events', '.launch.button');

  //  点击按钮弹出下拉框
  $(' .ui .dropdown').dropdown();

  	// auto change text according to Name and Device
  	$('#dataItemType').keypress(function() {
	  	var total = $('#dataItemDevice>option:selected').html() + "//" + $(this).val();
	  	$('#dataItemFullPath').val(total);
  	});

  	$('#dataItemDevice').change(function(){
			var total = $('#dataItemDevice>option:selected').html() + "//" + $('#dataItemType').val();
			$('#dataItemFullPath').val(total);
  	});	     
  
  	// refresh the content
  	//setTimeout(eventMessageRefresh, 1000);
  	
  	/*
  $('#container').highcharts({
    series: [{
    	
    },{
    	
    },{
    	
    },{
    	
    }]
	});
// the button action
	var i = 0;
	$('#button').click(function () {
    var chart = $('#container').highcharts();
    chart.series[0].addPoint(50 * (i % 3));
    i += 1;
	});
	*/
	
	/* Get the DataItems List*/
	var DataItems = $.ajax() 
	
	
	
	
	
	
	Highcharts.setOptions({
    global: {
        useUTC: false
    }
	});

	Highcharts.chart('container', {
    chart: {
        type: 'spline',
        animation: Highcharts.svg, // don't animate in old IE
        marginRight: 10,
        events: {
            /*load: function () {

                // set up the updating of the chart each second
                var series = this.series[0];
                setInterval(function () {
                    var x = (new Date()).getTime(), // current time
                        y = Math.random();
                    //series.addPoint([x, y], true, true);
                    if (series.data.length < 300) {
                     	series.addPoint([x, y]);
                     }else
                     {
                     	series.addPoint([x, y], true, true);
                     }
                }, 1000);
            }*/
            load: function() {
            	  // ajax code
            		var cur_series = this.series;
            	
            		setInterval( function() {
            		$.ajax({
            			type:"get",
            			url:"/analogCharts/",
            			async:true,
            			success: function(datum){
            				//console.log(datum[0].Value);
            				for (var i = 0; i < datum.length; i++) {
            				  console.dir(data);
            				  var data = datum[i];
            				  var serieId = data.DataItemId-1;
            				  var newPoint_X_String = (data.TimeStamp).replace(/T/, ' ').replace(/\..+/, '');

            				  var newPoint_X = (new Date(newPoint_X_String)).getTime();
            				  var newPoint_Y = data.Value;
            				  
            				  var serie = cur_series[serieId],
            				  		len = serie.points.length;
            				 
            				  //var lastPoint_X = serie.data[len-1].x,
            				  //		lastPoint_Y = serie.data[len-1].y;
            				  if (len > 0) {
            				  	var lastPoint_X = serie.points[len-1].x,
            				  			lastPoint_Y = serie.points[len-1].y;
            				  } else{
            				    var lastPoint_X = 0,
            				  			lastPoint_Y = 0;
            				  }
            				  if (lastPoint_X < newPoint_X) {
            				  	if (len < 300) {
            				    	serie.addPoint([newPoint_X, newPoint_Y]);
            				   } else {
            				   	  serie.addPoint([newPoint_X, newPoint_Y], true, true);
            				   }
            				  } else {
            				  	if (len < 300) {
            				    	serie.addPoint([lastPoint_X + 1000, 0]);
            				   } else {
            				   	  serie.addPoin([lastPoint_X + 1000, 0], true, true);
            				   }
            				  }
            				}
            			}
            	  });}, 1000);
            	  //setTimeout
            		//setTimeout(load(), 5000);
            }
        }
    },
    title: {
        text: 'Live random data'
    },
    xAxis: {
        type: 'datetime',
        tickPixelInterval: 150
    },
    yAxis: {
        title: {
            text: 'Value'
        },
        plotLines: [{
            value: 0,
            width: 1,
            color: '#808080'
        }]
    },
    tooltip: {
        formatter: function () {
            return '<b>' + this.series.name + '</b><br/>' +
                Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '<br/>' +
                Highcharts.numberFormat(this.y, 2);
        }
    },
    legend: {
        enabled: true
    },
    exporting: {
        enabled: true
    },
    series: [{
        name: '压差',
       	data: []
       	},{
        name: '风机电流',
       	data: []
       	},{
        name: '袋漏定位',
       	data: []
       	},{
        name: '粉尘排放',
       	data: []
       	}],
    credits: {
    	enabled: false
    }
	});
	
	setInterval(function () {
			//alert("Hi");
			messageTable.ajax.reload();
		}, 5000);
})



//function eventMessageRefresh(){
//	
//console.log("Refresh");
//}

</script>

很奇怪的情况,你可以试试改成res.send测试一下 这是res.json我查到的部分解释https://segmentfault.com/q/1010000009000325/a-1020000009003036 是否有可能是因为res.json最后的set导致的? 我觉得最起码两个Ajax不会冲突吧

跟ajax应该没关系,看起来也不像是res.json的问题,我猜应该是别的地方有个异步的end操作

@Yuki-Minakami 目前我修改了两个地方,现在没有这个报错了

  1. 把两个ajax都设置为同步的方式 async = false, 我过会儿再试一下打开会是怎样

  2. 在router中去掉了next,改为了

    router.get(’/’, function(req, res) { EventMessageModel.getEventMessages(20) .then(function(eventMessages) { res.setHeader(‘Content-Type’, ‘application/json’); res.send(JSON.stringify(eventMessages)); return; }); });

@2linziyi2 谢谢你的回复,我发现两个Ajax在全部设置为异步的时候就发生冲突了,该怎么优化呢?两个Ajax都是放在setInterval里面用来读取实时数据,刷新highchart和datatable的

问题应该是在 then 里面 出现了异常,然后在 catch 中 又执行了 next,导致两次 writeHead 操作。。

你可以試一下

router.get('/', (req, res, next) => EventMessageModel.getEventMessage(20)
   // res.json 會設header為json,同時如果eventMessages是object,就不用json。stringify了
  .then(res.json)
)

上面可能是我編程的風格,你可以應該在EventMessageModel前加return

router.get('/', function(req, res, next) {
  return EventMessageModel.getEventMessages(20)
    .then(function(eventMessages) {
        res.json(eventMessages);
     });
    // .catch(next);
	// 在router裡面應該就不用catch(next)除非是寫中間件或者你已經知道會有哪些錯誤可能會出現才寫catch來反饋錯誤訊息
});

@alphaXkiller 谢谢您的解释,对于middleware我的理解不够深刻,导致了前面遇到的问题,考虑到实时性,我现在转向用socket.io来实现这个功能,效果还不错

<script>
		$(document).ready( function () {
		 	var socket = io();
			$('form').submit(function(){
  				socket.emit('chat message', $('#m').val());
  				$('#m').val('');
  				return false;
			});
			
			var messageTable = $('#tbEventMessage').DataTable({
			});
			
			
			function UpdateTable(){
				socket.emit('eventRequest', 'update');
			}
			
			UpdateTable();
			
			
			socket.on('chat message', function(msg) {
				$('#messages').append($('<li>').text(msg));
			});
			
			socket.on('eventCallback', function(feedback){
				socket.emit('chat message', 'Received the feedback');
				messageTable.clear();
				for(var i = 0; i < feedback.length; i++)
				{
					var data = feedback[i];
					socket.emit('chat message', '  Record: ' + data.EventID);
					messageTable.row.add([
							data.EventID,
							data.PrecursorId,
							data.DataItemId,
							data.ZoneNumber,
							data.ConditionId,
							data.SubConditionId,
							data.State,
							(data.ActiveTime).replace(/T/, ' ').replace(/\..+/, ''),
							(data.EventTime).replace(/T/, ' ').replace(/\..+/, ''),
							data.Severity,
							data.Threshold,
							data.Message
					]).draw(false);
				}
			});
		});
	</script>

index.js

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

var EventMessageModel = require('./models/eventMessages');

app.get('/', function(req, res) {
   res.sendFile(__dirname + '/index.html');
});


io.on('connection', function(socket) {
    console.log('a user connected');
    socket.on('disconnect', function() {
	    console.log('user disconnected');
    });
    socket.on('chat message', function(msg){
	    console.log('message: ' + msg);
	    io.emit('chat message', msg);
    });
    socket.on('eventRequest', function(msg){
	    console.log('eventRequest:' + msg);
	    EventMessageModel.getEventMessages(20).then(function(eventMessages) {
		   io.emit('eventCallback', eventMessages);
	    });
    })
});

http.listen(3000, function() {
    console.log('listen on *3000');
});

@newonejoe socket.io是用來处理实时数据交换,譬如是聊天室,股票数据呈现之类的。如果只是用于提交表格的话,socket.io可能会导致资源浪费

@alphaXkiller 我用socket.io个来推送warning/error 信息到HMI,实时性要求高一点, 表格只是显示的手段,没有数据提交

回到顶部