大胆猜想,小心求证
随着编程经验的增加,我越来越觉得调试BUG的过程和侦探查案类似,需要:大胆猜想,小心求证。
昨天给用户上传增加了一个新功能:使用event source来推送当前的上传进度,防止用户一直傻等。结果本地调试一切正常,但是部署到线上就出现进度事件捕获不到的情况。
首先,我问了AI(ChatGPT和Gemini)。不得不承认,AI的缺陷主要有两个:
- 它的回答从来都是“信心满满”,可能80%的推理下是对的,但是20%的错误反而会误导你;
- 和AI交互需要清晰明确地描述问题背景,但是有些实际情况很复杂,很难通过语言文字进行表达。
所以,AI绕了一圈,并没有帮我找到问题根源,反而产生了一堆垃圾信息。所以,我又回归到古法编程,变身为Bug侦探。
后端使用Spring Boot,我在建立SSE连接时会推送一个open事件:
var emitter = new SseEmitter(30 * 60 * 1000L);
// 立即发送一条建立连接的消息
emitter.send(SseEmitter.event().name("open").data("SSE established: " + key));这个推送是正常的,前端网页能收到了open事件。但是,上传时的进度却收不到,进度推送的代码如下:
var eventBuilder = SseEmitter.event().name("progress").data(data);
emitter.send(eventBuilder);两者唯一的区别就是一个使用了open事件,一个使用了progress事件。但我本地开发都能收到,因此,这不是代码的问题,而是部署的问题。本地环境和线上环境的唯一差别就是线上使用了Nginx作为中间代理,又因为event source需要在Nginx中进行额外配置:
# event source 配置
location ^~ /api/orders/excel/uploadProgress/ {
proxy_pass http://tag_backend;
# 1. 核心:禁用缓冲,确保数据实时推送
proxy_buffering off;
proxy_cache off;
# 2. 核心:保持长连接,防止协议退化
proxy_http_version 1.1;
proxy_set_header Connection "";
# 3. 核心:延长读取超时时间
proxy_read_timeout 300s;
}这个配置也是没有问题的,因为open事件可以收到。
我突然灵光一闪,大胆猜测了一个想法:因为我的页面中有两个event source订阅,我Nginx只配置了一个订阅,另外一个还没有配置,是不是需要两个都配置好才行呢?然后,我就将另外一个event source订阅也在Nginx中进行配置了:
# event source 配置
location ^~ /api/orders/pdfzip/uploadProgress/ {
proxy_pass http://tag_backend;
# 1. 核心:禁用缓冲,确保数据实时推送
proxy_buffering off;
proxy_cache off;
# 2. 核心:保持长连接,防止协议退化
proxy_http_version 1.1;
proxy_set_header Connection "";
# 3. 核心:延长读取超时时间
proxy_read_timeout 300s;
}一个是对excel上传进度进行配置,一个是对zip文件上传进度进行配置。重新部署后,奇迹出现了,进度推送正常了!
真是奇怪,说真的,底层原理我暂时还没弄清楚,但是这个思维过程让我震撼!
这就是编程的乐趣!不是吗?和侦探查案一样,编程是一个严谨的推理工程,排除法在这里起到了非常关键的作用。另外,更重要的是,我们还需要一些大胆的猜想(想象),甚至推翻直觉。