记一次 Nginx 调参的踩坑经历

最近在基于SSE(Server Sent Events)做服务端单向推送服务,本地开发时一切顺利,但是在部署到预发环境时就碰到1个很诡异的问题,这里需要简单介绍下我们的整体架构:

整体架构

架构

可以看到所有的请求都会先到统一的网关层(对应 example.com 这个一级域名),然后发到不同的应用对应的docker镜像上,这里不同的应用可以简单地用不同的域名来做表示,例如应用 A 的域名是A.example.com,应用 B 的域名是 B.example.com,且这里的每1个应用都是1个SPA单页应用,这样的话前端和服务端就是完全分离的,前端这边完全掌控页面和路由的跳转,对于数据获取和更新只需要请求对应的接口和服务即可,这也算是现在比较流行的一种架构了。
因为历史原因,我们的服务有多个,且这些服务的域名是不一样的,例如对于应用A来说,所依赖的底层服务有 serviceA(域名是serviceA.example.com)和serviceB(域名是serviceB.example.com),所以在应用A的docker上会存在1个 Nginx ,用来对A.example.com 下的不同接口的请求做反向代理,确保能转发到不同的服务上。
例如当用户请求A.example.com/doc/update/这个接口时,本质上会发送请求到 doc.example.com/update这个接口上,并得到数据。
好了,背景介绍得差不多了,现在开始上重点。

真实场景

现在我们做了1个 SSE(Server Sent Events)服务在doc.example.com/sse,那么我们需要Nginx将 A.example.com/doc/sse给转发到doc.example.com/sse 上即可
SSE的全称是(Server Sent Events),简单来说服务器发送事件,是客户端与服务端建立单向的长连接通信的一种方式,客户端可以通过 EventSource 来订阅事件通知,等待服务端去推送消息
在咨询了ChatGPT 4之后,最精简的配置如下:

server {
    listen  80;
    charset utf-8;
    ... # 省略配置信息

    location /doc/sse {        
        # 转发到对应的域名下
        proxy_pass https://doc.example.com/sse; 

        # Disable buffering for SSE
        proxy_buffering off;
        
       # Other necessary SSE headers
        proxy_set_header Cache-Control 'no-cache';
        proxy_set_header Connection 'keep-alive';

        # Standard proxy headers
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
 }

但是在连接后就发现1个很奇怪的问题,sse 无法连接,会被重定向到 A.example.com/sse 这个域名下,而不是我们想要的 doc.example.com/sse
上面的配置看起来无比正确,但就是存在问题。那么话不多说,直接二分排查。

这里抽象一个解决的方法论,即先保留一个最小的正确问题的现场,然后通过二分搜索的方式去找到具体的原因

问题本质

经过层层筛选,最后发现问题出在proxy_set_header Host $http_host;这条语句上。
当在 Nginx 中同时使用proxy_set_headerproxy_pass指令时,Host 头部的处理步骤如下:

第一步:请求到达 Nginx

客户端发起请求,该请求到达运行 Nginx 的服务器。该请求会包含一个 Host 头部,通常是用来指定服务器的域名或IP地址。

第二步:匹配 Location 块

Nginx 根据请求的 URI 匹配相应的 location 块。例如,如果请求的是 /doc/sse,Nginx 将匹配包含proxy_passproxy_set_header 指令的 location /doc/sse 块。

第三步:处理 proxy_set_header 指令

如果在 location 块中使用了 proxy_set_header Host $http_host; 指令,Nginx 将修改或添加 Host 请求头部,将其值设置为 $http_host 变量的值。这个变量通常包含客户端在请求中发送的 Host 头部的值。

第四步:处理 proxy_pass 指令

proxy_pass 指令告诉 Nginx 将请求转发到指定的后端服务。如果配置为 proxy_pass https://doc.example.com/sse,Nginx 将请求转发到 https://doc.example.com/sse

第五步:设置请求头部

重点来了,在将请求转发给后端服务之前,Nginx 将根据 proxy_set_header 指令设置的值来修改请求头部。在这个过程中,Nginx 会将 Host 头部设置为客户端请求中的 Host 头部的值,而不是 proxy_pass 中指定的后端服务的域名。
也就是说,我们请求的地址经历了以下的变化:

  1. A.example.com/doc/sse
  2. doc.example.com/sse
  3. A.example.com/sse(由proxy_set_header执行)

那么相当于发生了1次不受 Nginx 管控的重定向。

正确答案:

最精简的完整配置如下:

location /doc/sse {        
        proxy_pass https://doc.example.com/sse; 

        # Disable buffering for SSE
        proxy_buffering off;
    }

这里可能有的同学会好奇,为什么一定要关闭代理缓存呢?如果不关闭会怎么样呢?下面我们来简单讲讲:

为什么要关闭代理缓存?

对于(SSE)来说,关闭代理缓冲非常重要,原因主要在于SSE的工作机制和数据流的特性。

  1. SSE工作机制: SSE允许服务器通过一个持久的HTTP连接向客户端实时推送数据。服务器发送的数据流是一个持续的过程,不是一次性完成的。
  2. 代理缓冲的影响: 如果代理服务器对传入的响应进行缓冲,它可能会等待缓冲区填满或达到某个特定的数据量后,才将数据一次性发送给客户端。这样做的结果是客户端不能实时接收到服务器推送的数据,从而破坏了SSE的实时性。
  3. 实时性要求: SSE的主要用途是为了实现实时通信。如果代理服务器对数据进行缓冲,则实时通信的效果会被大大降低,因为客户端接收数据的速度会受到影响。
  4. 连接保持: 除了实时性之外,SSE连接需要保持打开状态,以便服务器可以持续发送数据。如果代理服务器对连接进行了不当的处理(例如,由于长时间不活动而关闭连接),这也可能干扰SSE的正常工作。

因此,对于SSE来说,关闭代理服务器的响应缓冲是确保数据能够及时、连续地发送给客户端的关键。这样可以保持数据流的连续性,确保客户端能够实时接收到服务器端发送的每一条消息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/265866.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2. 结构型模式 - 桥接模式

亦称: Bridge 意图 桥接模式是一种结构型设计模式, 可将一个大类或一系列紧密相关的类拆分为抽象和实现两个独立的层次结构, 从而能在开发时分别使用 问题 抽象? 实现? 听上去挺吓人? 让我们慢慢来&#x…

2023年软件测试已经崩盘了吗?为什么很难找到工作?

最近后台很多粉丝给我留言: 2023年软件测试已经崩盘了吗,为什么都找不到工作了? 确实,今年经济大环境不好,企业也都在降本增效,如果技术能力还在被应届生竞争岗位的阶段,只会越来越难。 找不…

3d max高质量渲染时,硬件的要求有什么?

渲染过程中,想要追求,效果图高质量渲染,高效率渲染的过程中,3d max高清渲染不只是三维软件的一个要求,对于本地计算机的硬件要求配置也是很重要的。 今天,小编带大家来聊聊3d max高质量渲染过程中&#xff…

20 Vue3中使用v-for遍历普通数组

概述 使用v-for遍历普通数组在真实开发中还是比较常见的。 基本用法 我们创建src/components/Demo20.vue&#xff0c;代码如下&#xff1a; <script setup> const tags ["JavaScript", "Vue3", "前端"] </script> <template…

单例模式实现

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;JavaEE &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 单例模式 1. 什么是单例模式2. 饿汉模式3.…

机器学习的一些有趣的点【异常检测】

机器能不能知道自己不知道&#xff0c;而不是给出判断中的一种&#xff1f; Classifier&#xff08;分类&#xff09;Anomaly Detection&#xff08;异常检测&#xff09; 机器能不能说出为什么知道&#xff1f; 有时候可能是因为数据的问题导致了这种错觉。 机器学习是否会有错…

虾皮跨境电商的收款方式及选择指南

虾皮&#xff08;Shopee&#xff09;作为一家知名的跨境电商平台&#xff0c;为卖家提供了多种收款方式&#xff0c;以满足不同卖家的需求。本文将介绍虾皮跨境电商平台的主要收款方式&#xff0c;并提供选择指南&#xff0c;帮助卖家根据自身需求和目标市场选择最合适的收款方…

机器学习---K近邻算法

1. KNN算法 K近邻算法&#xff0c;即K-Nearest Neighbor algorithm&#xff0c;简称KNN算法&#xff0c;是一个理论上比较成熟的方法&#xff0c;也 是最简单的机器学习算法之一&#xff0c;1968年由 Cover 和 Hart 提出。 该方法的思路是&#xff1a;如果一个样本在特征空间…

人工智能中GAN 的五大有趣应用

引言 你能看出这张照片中面部的共同点吗&#xff1f; 这些人都不是真实存在的&#xff01;这些面部图像都是由 GAN 技术生成的。 “GAN” 这个词是由 Ian Goodfellow 在 2014 年提出的&#xff0c;但相关概念早在 1990 年就存在了&#xff08;Jrgen Schmidhuber 开创&#xf…

图像识别中的 Vision Transformers (ViT)

引言 Vision Transformers (ViT) 最近已成为卷积神经网络(CNN) 的竞争替代品&#xff0c;而卷积神经网络 (CNN) 目前在不同的图像识别计算机视觉任务中处于最先进的水平。ViT 模型在计算效率和准确性方面比当前最先进的 (CNN) 模型高出近 4 倍。 Transformer 模型已成为自然语…

【vtkWidgetRepresentation】第十七期 vtkDistanceRepresentation

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 前言 本文分享vtkDistanceRepresentation相关内容,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U^)ノ~YO 目录 前言 1. vtkDistanceRep…

ESP8266网络相框采用TFT_eSPI库TJpg_Decoder库mixly库UDP库实现图片传送

用ESP8266和TFT_ESPI模块来显示图片数据。具体来说&#xff0c;我们将使用ILI9431显示器作为显示设备&#xff0c;并通过UDP协议将图片数据从发送端传输到ESP8266。最后&#xff0c;我们将解析这些数据并在TFT屏幕上显示出来。在这个过程中&#xff0c;我们将面临一些编程挑战&…

SpringBoot+JaywayJsonPath实现Json数据的DSL(按照指定节点表达式解析json获取指定数据)

场景 若依前后端分离版手把手教你本地搭建环境并运行项目&#xff1a; 若依前后端分离版手把手教你本地搭建环境并运行项目_前后端分离项目本地运行-CSDN博客 在上面搭建SpringBoot项目的基础上&#xff0c;并且在项目中引入fastjson、hutool等所需依赖后。 Jayway JsonPat…

05. Springboot admin集成Actuator(一)

目录 1、前言 2、Actuator监控端点 2.1、健康检查 2.2、信息端点 2.3、环境信息 2.4、度量指标 2.5、日志文件查看 2.6、追踪信息 2.7、Beans信息 2.8、Mappings信息 3、快速使用 2.1、添加依赖 2.2、添加配置文件 2.3、启动程序 4、自定义端点Endpoint 5、自定…

【数据结构入门精讲 | 第十六篇】并查集知识点及考研408、企业面试练习

上一篇中我们进行了散列表的相关练习&#xff0c;在这一篇中我们要学习的是并查集。 目录 概念伪代码选择题填空题编程题7-1 朋友圈R7-1 笛卡尔树R7-2 部落R7-3 秀恩爱分得快 在许多实际应用场景中&#xff0c;我们需要对元素进行分组&#xff0c;并且在这些分组中进行查询和修…

常用Python自动化测试框架有哪些?优缺点对比

随着技术的进步和自动化技术的出现&#xff0c;市面上出现了一些自动化测试框架。只需要进行一些适用性和效率参数的调整&#xff0c;这些自动化测试框架就能够开箱即用&#xff0c;大大节省了测试时间。而且由于这些框架被广泛使用&#xff0c;他们具有很好的健壮性&#xff0…

代码随想录第三十九天(一刷C语言)|零钱兑换完全平方数

创作目的&#xff1a;为了方便自己后续复习重点&#xff0c;以及养成写博客的习惯。 一、零钱兑换 思路&#xff1a;参考carl文档 1、确定dp数组以及下标的含义&#xff1a;凑足总额为j所需钱币的最少个数为dp[j]。 2、确定递推公式&#xff1a;凑足总额为j - coins[i]的最…

先进制造身份治理现状洞察:从手动运维迈向自动化身份治理时代

在新一轮科技革命和产业变革的推动下&#xff0c;制造业正面临绿色化、智能化、服务化和定制化发展趋势。为顺应新技术革命及工业发展模式变化趋势&#xff0c;传统工业化理论需要进行修正和创新。其中&#xff0c;对工业化水平的判断标准从以三次产业比重标准为主回归到工业技…

WEB 3D技术 three.js 通过lil-gui 控制x y z轴数值 操作分组 设置布尔值控制 颜色材质控制

上文 WEB 3D技术 three.js 通过lil-gui管理公共事件中 我们用 lil-gui 处理了一下基础事件和按钮的管理 那么 本文 我们来具体说说它能做的其他事 我们先将基础代码改成这样 import ./style.css import * as THREE from "three"; //引入lil-gui import { GUI } fro…

web逆向经验

一、JS逆向调试流程 如果网页有跳转&#xff0c;必须勾选 preservelog 防止丢包看一下有没有框架 右键查看框架源代码(弹出式登陆界面)登陆尽量使用错误密码 防止跳转查看关键登陆包 分析哪些参数是加密的使用别的浏览器分析哪些参数是固定的值初步猜测加密方法搜索&#xff0…