基于Java的Web应用远程下载TXT文件出现重复条目问题排查
多服务器/负载均衡环境下TXT下载重复问题排查与调试方案
问题现象
基于Java的Web应用在远程多服务器/负载均衡环境中下载TXT文件时出现内容重复,但本地测试完全正常,且服务器上的源文件本身无重复条目:
- 源文件内容:
Test 123 Test 456
- 下载后文件内容:
Test 123 Test 456 Test 123 Test 456
初步怀疑是下载逻辑的JS代码在远程连接下出现异常,导致数据被莫名拼接两次。
相关代码
JS下载逻辑
jQuery('#submit-btn').on('click', function() { var name = jQuery(NAME_ID).val(); var request = new XMLHttpRequest(); request.open('POST', getUrl('search'), true); // 调用后端接口获取数据 request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); request.responseType = 'blob'; request.onload = function(e) { if (this.status === 200) { var blob = this.response; var filename = ""; var disposition = this.getResponseHeader('Content-Disposition'); if (disposition && disposition.indexOf('attachment') !== -1) { var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/; var matches = filenameRegex.exec(disposition); if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, ''); } if (window.navigator.msSaveOrOpenBlob) { window.navigator.msSaveBlob(blob, filename); } else { var downloadLink = window.document.createElement('a'); var contentTypeHeader = request.getResponseHeader("Content-Type"); downloadLink.href = window.URL.createObjectURL(new Blob([blob], { type: contentTypeHeader })); downloadLink.download = filename; document.body.appendChild(downloadLink); downloadLink.click(); document.body.removeChild(downloadLink); } } }; request.send("name="+name); });
后端Java接口
@RequestMapping(value = "/search", method = RequestMethod.POST, produces = "text/plain") public @ResponseBody String search(HttpServletRequest request, HttpServletResponse response) { String log = ""; String fileName = ""; String useragent = "" + request.getHeader("user-agent"); if (request.getParameter("name") != null) { fileName = request.getParameter("name"); } try { log = readLogContent(fileName.trim()); StringBuilder builder = new StringBuilder(50); if (useragent != null && useragent.indexOf("MSIE 6") == -1) { builder.append("attachment; filename="); } else { builder.append("inline; filename="); } builder.append(fileName); response.setHeader("Content-Disposition", builder.toString()); response.setContentType(MimeTypes.getMimeType("txt")); OutputStream os = response.getOutputStream(); try { os.write(log.getBytes(Charset.forName("UTF-8"))); os.flush(); } finally { os.close(); } } catch (IOException e) { logger.debug(e); } return ""; }
问题排查与修复
核心问题定位:后端双重输出冲突
后端代码存在明显逻辑矛盾:
- 方法标注了
@ResponseBody,Spring MVC会自动将方法返回值(空字符串"")写入响应体 - 代码中又手动通过
OutputStream写入了文件内容 - 本地环境可能因Tomcat缓冲区或响应处理机制未显现问题,但在远程负载均衡环境下,代理服务器的响应拼接逻辑将两次输出合并,导致内容重复
修复方案:
移除@ResponseBody注解,将方法返回类型改为void,因为已经手动处理了响应输出,不需要Spring再介入:
@RequestMapping(value = "/search", method = RequestMethod.POST, produces = "text/plain") public void search(HttpServletRequest request, HttpServletResponse response) { // 保留原有业务逻辑,删除最后的return "";语句 }
其他可能的排查方向
- JS事件重复绑定:远程环境下页面可能被多次渲染,导致按钮点击事件被绑定多次,触发重复请求。可修改JS代码,绑定前先解除原有绑定:
jQuery('#submit-btn').off('click').on('click', function() { // 原有逻辑不变 }); - 负载均衡请求重试:检查负载均衡器配置,是否存在请求超时重试机制,导致后端被重复调用,返回两次内容被拼接。
JS调试方案(查看Blob内容与请求详情)
1. 直接查看后端响应
打开浏览器开发者工具(F12)→ 切换到网络标签 → 筛选XHR请求,找到search接口:
- 查看
响应标签,直接确认后端返回的内容是否已经重复——这能快速区分是后端问题还是JS处理问题 - 查看
请求标签,确认请求参数、发送次数是否正常
2. 打印Blob内容
在JS的request.onload函数中添加代码,将Blob转换为文本并打印到控制台:
request.onload = function(e) { if (this.status === 200) { var blob = this.response; // 调试代码:打印Blob内容 const reader = new FileReader(); reader.onload = () => console.log("Blob原始内容:", reader.result); reader.readAsText(blob); // 原有下载逻辑继续执行 // ... } };
3. 检查事件绑定次数
在浏览器控制台执行以下代码,查看按钮的点击事件绑定情况:
// jQuery 3.x及以上版本 console.log(jQuery('#submit-btn').get(0).onclick); // 或查看Elements标签中按钮的"事件监听器"面板,确认是否有多个click事件
内容的提问来源于stack exchange,提问作者yonikawa
相关产品推荐
相关产品推荐

