Javascript Event Listeners失效:聊天监控功能异常求助
问题:EventSource聊天监控页面突然失效
我维护的一个监控新评论的聊天数据库功能,正常运行两年后,近期所有带事件监听器的页面突然失效。
前端页面代码
<script> var source = new EventSource('mychat.cfm'); source.addEventListener('message', function(e){ document.body.innerHTML = e.data + document.body.innerHTML; }); function select(id,style) { //set the question live and turn off any others document.querySelectorAll('div').forEach(function(item) { item.className = 'option'; }) var div = document.getElementById(id); div.classList.replace("option", style); console.log(div); } </script>
后端mychat.cfm代码
<cfcontent type="text/event-stream"> <script> function select(id,style) { var div = document.getElementById(id); div.classList.replace("option", style); //setTimeout(location.reload.bind(location), 300); return false; } </script> <CFquery datasource="chat" name="topmesg" > SELECT max(id) as topid FROM chats where DATE_SUB(CURDATE(),INTERVAL 5 DAY) <= timestamp; </CFquery> <cfset topid=#topmesg.topid#-10> <cfoutput>#topid#</cfoutput> <cfsetting requesttimeout="800"> <cffunction name="sendData"> <cfoutput>data:<b>#author#</b> | #dateTimeFormat(Dateadd("h",1,mesg.timestamp), "ddd dd mmm - h:nn a")# <br> #mesg.message#</cfoutput> <cfflush> </cffunction> <cfset fromDate = Now()> <cfset toDate = DateAdd("n", 30 , Now())> <cfloop from="#fromDate#" to="#toDate#" index="i" step="#CreateTimeSpan(0,0,0,1)#"> <cfoutput>#i#</cfoutput> <CFquery datasource="chat" name="mesg" maxrows="10"> SELECT * FROM chats where id > #topid# order by id desc limit 0,11; </CFquery> <cfloop query="mesg"> <cfset sendData()> <cfset topid=#id#> </cfloop> <cfthread action="sleep" duration="1000"/> <cfflush> </cfloop>
当前运行环境
- OS: Linux (4.14.252-131.483.amzn1.x86_64)
- Java Version: 64bit 1.8.0_92 (Oracle Corporation) 64bit
- Tomcat Version: Apache Tomcat/8.0.35
- Lucee Version: 6.0.0.585
失效原因排查
- SSE响应格式违规:mychat.cfm开头输出了
<script>标签,SSE要求响应必须是纯文本事件流,任何额外HTML/JS代码都会破坏EventSource解析逻辑,导致连接异常终止。 - 无效初始输出:
<cfsetting>前直接输出的#topid#以及循环里的#i#时间戳,都不属于SSE规范的data:字段格式,会被判定为无效数据,触发连接错误。 - Lucee版本兼容性问题:近期升级到Lucee 6.0.0.585,旧代码的输出缓冲、
<cfflush>执行逻辑可能因版本变更出现异常,导致SSE流无法正确推送。 - 查询逻辑冗余:查询中
maxrows="10"和limit 0,11存在逻辑冲突,可能导致数据重复或漏查,同时<cfthread sleep>会额外消耗资源,影响连接稳定性。
解决办法
1. 清理SSE响应中的非规范内容
- 删除mychat.cfm开头的
<script>标签块,确保响应仅包含符合SSE格式的内容。 - 移除初始的
<cfoutput>#topid#</cfoutput>和循环内的<cfoutput>#i#</cfoutput>,避免无效数据干扰事件流解析。
2. 修正SSE事件流格式
SSE要求每个事件结尾必须有两个换行符,修改sendData函数:
<cffunction name="sendData"> <cfoutput>data:<b>#author#</b> | #dateTimeFormat(Dateadd("h",1,mesg.timestamp), "ddd dd mmm - h:nn a")# <br> #mesg.message#</cfoutput> <cfoutput>#chr(10)##chr(10)#</cfoutput> <!-- SSE事件结束标记 --> <cfflush> </cffunction>
3. 优化后端逻辑
- 将
<cfthread action="sleep" duration="1000"/>替换为<cfset sleep(1000)>,减少线程资源消耗。 - 统一查询的分页逻辑,将
maxrows="10"和limit 0,11改为limit 10,避免逻辑冲突:<CFquery datasource="chat" name="mesg"> SELECT * FROM chats where id > #topid# order by id desc limit 10; </CFquery>
4. 验证环境配置
- 确认Lucee的
requesttimeout设置生效,避免长连接提前超时。 - 检查Tomcat连接器配置,确保
keep-alive功能开启,维持SSE所需的长连接。
5. 前端添加错误监听
增加错误捕获逻辑,方便排查连接问题,可选添加重连机制:
source.addEventListener('error', function(e) { console.error('EventSource连接错误:', e); if (e.readyState === EventSource.CLOSED) { // 5秒后尝试重连 setTimeout(() => { source = new EventSource('mychat.cfm'); }, 5000); } });
内容的提问来源于stack exchange,提问作者Nowski
相关产品推荐
相关产品推荐

