1. 前言

在使用 Spring Boot 开发流式接口(Server-Sent Events)时,我们遇到了一个令人困惑的问题:每次 SseEmitter 完成后,都会触发第二次请求,导致重复请求检测机制误报。本文将详细记录问题的发现、分析过程以及最终的解决方案。

2. 系统架构背景

2.1 请求处理架构

我们的系统采用了标准的 Spring Boot 微服务架构,其中包含一个关键的请求拦截器组件:

@Component
@Slf4j
public class RequestHandlerInterceptor extends HandlerInterceptorAdapter {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {// 1. API 签名校验// 2. 重复请求过滤// 3. 用户权限验证// 4. 请求日志记录return true;}
}

RequestHandlerInterceptor 的主要职责:

  • API 签名校验:验证请求的数字签名,确保请求的完整性和来源可信
  • 重复请求过滤:基于 Redis 缓存的防重复提交机制,防止用户误操作
  • 用户权限验证:检查用户登录状态和访问权限
  • 请求日志记录:记录关键请求信息用于审计和问题排查

2.2 系统部署架构

客户端 → Nginx → Spring Boot 微服务 → RequestHandlerInterceptor → Controller

3. 问题现象

3.1 初始症状

在我们的导出服务中,使用 SseEmitter 实现流式 PDF 生成功能时,RequestHandlerInterceptor 的 preHandle 方法出现了异常的重复调用现象

@PostMapping("/monthReport/insurance/v3/pdf/stream")
public SseEmitter reportInsurancePDFV3Stream(@RequestBody ReportInsuranceV3StreamDTO dto) {// SseEmitter 实现
}

RequestHandlerInterceptor 日志显示的异常行为:

2025-07-07 17:00:33.245  INFO  [XNIO-1 task-9]  RequestHandlerInterceptor.preHandle() - 第一次调用
2025-07-07 17:00:33.448  INFO  [XNIO-1 task-9]  === reportInsurancePDFV3Stream START ===
2025-07-07 17:01:21.978  INFO  [async-IO-1]    === CALLING emitter.complete() ===
2025-07-07 17:01:22.046  INFO  [XNIO-1 task-13] RequestHandlerInterceptor.preHandle() - 第二次调用!
2025-07-07 17:01:22.054  WARN  [XNIO-1 task-13] 重复请求检测触发,客户端信息:...
2025-07-07 17:01:22.087  INFO  [XNIO-1 task-14] === SseEmitter COMPLETION ===

3.2 关键发现

  1. 拦截器重复调用RequestHandlerInterceptor.preHandle() 方法被调用了两次
  2. 时间差异emitter.complete() 调用和第二次拦截器调用之间有明显的时间间隔
  3. 线程差异:第二次拦截器调用在不同的线程中执行
  4. 重复检测触发:第二次调用被重复请求检测机制拦截,导致异常抛出

4. 问题分析历程

4.1 第一阶段:排除外部因素

面对这个奇怪的现象,我们首先怀疑是外部因素导致的重复请求。

4.1.1 排除前端重试机制

最初怀疑是前端 EventSource 存在重试逻辑:

eventSource.onerror = function(event) {// 可能的重试逻辑startExport();
};

验证方法:使用 curl 直接测试

为了排除前端重复调用的可能性,我们绕过前端,直接使用 curl 命令测试接口:

curl -X POST "http://localhost:8080/api/stream" \-H "Content-Type: application/json" \-H "Authorization: Bearer eyJhbI1NiIsInR5cCI6IkpXVCJ9..." \-H "X-Ca-Nonce: 1234567890" \-d '{"patientId":"176900913670569984","startTime":"2023-07-01","endTime":"2023-07-31"}'

结果:问题依然存在!

即使绕过前端,直接使用 curl 访问,RequestHandlerInterceptor.preHandle() 仍然被调用了两次,这证明问题不在前端。

4.1.2 排除 Nginx 配置问题

接下来怀疑是 Nginx 的配置或重试机制导致的:

  • Nginx 的 proxy_retry 配置
  • Nginx 的超时重试机制
  • Nginx 的负载均衡重试

验证方法:绕过 Nginx 直接访问微服务

我们直接访问微服务端口,完全绕过 Nginx:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/95724.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/95724.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/95724.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

心路历程-三个了解敲开linux的大门

学习前都爱唠叨一番: 了解一下:互联网的发展是离不开服务器的,而服务器的系统主流的还是Linux;这个是有数据进行支撑的;这个只是作为了解而已,我们并不买课,也不做什么买卖的行为,仅…

关于“双指针法“的总结

笔者这些天终于达成了只狼的全成就,甚是欢喜。然而乐极生悲,最近做了些算法题,竟没有一道靠自己做出来。感觉算法题常常用到“双指针法”呢……为什么到现在我还是做不出来这些算法题……今天就来试着总结一下它的使用场景吧。快慢指针法又名…

基于51单片机的智能吊灯

基于 51 单片机的智能吊灯设计与实现论文简纲一、引言1.1 研究背景与意义阐述传统照明设备在节能性、智能化方面的不足,结合智能家居产业发展趋势,说明设计基于 51 单片机的智能吊灯对提升生活便利性、降低能耗的现实意义。1.2 国内外研究现状简要介绍当…

CF每日三题(1500-1700)

1792C 逆向思维1036D 前缀和尺取1598D 组合数学取三元组 将二元组放在坐标系中更好找到规律 1792C 思维 1500 参考题解 正难则反 注意是对一个排列进行操作,最后还原成1,2,…,n 每次选两个数字很难想,反着想就是把1-n的排列变成所给数组的逆操作&#x…

Boost搜索引擎项目(详细思路版)

目录 项目相关背景 搜索引擎原理技术栈和项目环境 导入数据到自己的本地 数据去标签与数据清洗模块 Enumfile(src_path, &file_list)递归式写入 Parsehtml(file_list, &results)去标签 bool Parsetitle(const string& file, string* title)拆分标题 bool Pa…

AI产品经理面试宝典第69天:大模型稳定性评估与AI伦理挑战面试题全解析

1. AI伦理与技术挑战 1.1 问:你认为AI的最大挑战是什么? 答:AI面临的最大挑战是算法偏见与模型黑箱问题。具体表现为: 数据偏见放大:训练数据中隐含的性别、种族等偏见会被模型继承,如招聘算法中的性别歧视案例 决策透明性缺失:深度学习模型的可解释性不足,医疗诊断场…

【build】RDK构建系统v0.1 (持续更新。。。。)

一、 项目概述RDK构建系统是一个用于构建和定制嵌入式系统的自动化工具,通过简单的命令行操作,您可以完成从下载依赖包、定制根文件系统、构建内核到打包镜像的完整流程。该系统采用模块化设计,提供了丰富的配置选项,适用于不同的…

关于RSA和AES加密

RSA非对称加密 非对称加密不能传输大数据量,但比对称加密要安全,所以传输密码一般就是用的非对称加密 接口拿到RSA公钥然后再加密之后传给后端就好了 let crypt new JSEncrypt(); crypt.setPublicKey(res.message); // console.log(加密前:, data); let…

云蝠智能VoiceAgent:AI赋能售后服务场景的创新实践

引言:售后服务数字化转型的必然趋势在数字经济时代,售后服务已成为企业核心竞争力的重要组成部分。据统计,优质的售后服务能够提升客户留存率高达67%,同时降低客户获取成本约30%。然而,传统售后服务模式面临着人力成本…

C#控制台输入(Read()、ReadKey()和ReadLine())

下面我们来详细讲解 C# 中三种控制台输入方法:Console.Read()、Console.ReadKey() 和 Console.ReadLine() 的区别、原理、使用场景,并配上清晰的代码例子和运行结果说明。✅ 一、三者的根本区别(一句话总结)方法返回值读取方式是否…

Windows的Roaming文件夹的作用和Local/LocalLow的区别

📁 Roaming 文件夹的核心意义✅ 什么是“漫游”(Roaming)?跨设备同步:当用户登录到同一域内的不同 Windows 设备(如公司或学校的办公电脑)时,Roaming 文件夹中的数据会自动通过网络同…

【Java Web 快速入门】十一、Spring Boot 原理

目录Spring Boot 原理配置优先级Bean 管理获取 BeanBean 的作用域第三方 BeanSpring Boot 底层原理起步依赖自动配置核心原理实例说明例 1:自定义一个 “日志 starter”例 2:SpringBoot 自带的 spring-boot-starter-web关键总结Spring Boot 原理 配置优…

基于Redisson的分布式锁原理深度解析与优化实践

基于Redisson的分布式锁原理深度解析与优化实践 分布式环境下,锁的实现至关重要。本文将从技术背景与应用场景出发,结合核心原理、关键源码、实际示例,深入剖析Redisson分布式锁的实现机制,并给出性能优化建议,帮助后端…

室外 3DVG 基准

室外 3DVG基准(按重要性与被引用频率) Talk2Car / Talk2Car-3D (2019 / 衍生) — 对象 referral(驾驶场景) 说明:最早的自然语言 → 驾驶场景对象引用数据集之一(原 Talk2Car 是以 nuScenes 为底并提供自然…

Jenkins安装部署(Win11)和常见配置镜像加速

一、安装前准备 本文使用的Jenkins Windows一键安装包,JDK事先配置好环境变量,Jenkins版本: Jenkins下载地址:jenkins一键安装包v2-479-1.msi资源-CSDN下载 二、Jenkins安装部署 1、下载Jenkins ,点击下一步下一步…

Windows MCP.Net:革命性的 .NET Windows 桌面自动化 MCP 服务器

📋 目录 项目概述 核心技术架构 功能特性详解 技术实现亮点 安装与配置 实战应用场景 代码示例与API详解 性能优化与最佳实践 未来发展规划 总结 项目概述 在人工智能快速发展的今天,AI 助手与操作系统的深度集成成为了一个重要趋势。Window…

Java ArrayList的介绍及用法

十分想念顺店杂可。。。ArrayList 是 Java 集合框架中最常用的类之一,实现了 List 接口,底层基于动态数组实现,支持动态扩容,相比普通数组更灵活。以下是其详细介绍及用法:一、核心特性动态大小:无需预先指…

Docker 命令大全及使用场景总结

一、容器生命周期管理1. 创建并运行容器docker run [选项] 镜像名 [命令]常用选项:-d:后台运行(detached)-it:交互式终端(如 -it ubuntu bash)--name:指定容器名称-p 主机端口:容器端…

简单的 HTTPS 学习

简单的 HTTPS 学习 1. 需求 现在使用的服务是HTTP调用形式,服务可能会有调用外围https形式的服务,简单了解了一下,然后写了一个简单的例子进行记录。 HTTP(超文本传输协议) 是一种用于传输超文本的应用层协议&#…

[系统架构设计师]系统质量属性与架构评估(八)

[系统架构设计师]系统质量属性与架构评估(八) 一.软件系统质量属性 1.基本概念 软件系统质量属性:可测量或可测试的属性 开发期质量属性,运行期质量属性面向架构评估的质量属性:1.可用性: 提升策略 错误检测…