精准扶贫网站建设目的,周末做兼职上什么网站找,如何经营一个购物网站,网站建设工作函最近在基于SSE#xff08;Server Sent Events#xff09;做服务端单向推送服务#xff0c;本地开发时一切顺利#xff0c;但是在部署到预发环境时就碰到1个很诡异的问题#xff0c;这里需要简单介绍下我们的整体架构#xff1a;
整体架构 可以看到所有的请求都会先到统一…最近在基于SSEServer 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个 SSEServer 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 SSEproxy_buffering off;# Other necessary SSE headersproxy_set_header Cache-Control no-cache;proxy_set_header Connection keep-alive;# Standard proxy headersproxy_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_header和proxy_pass指令时Host 头部的处理步骤如下
第一步请求到达 Nginx
客户端发起请求该请求到达运行 Nginx 的服务器。该请求会包含一个 Host 头部通常是用来指定服务器的域名或IP地址。
第二步匹配 Location 块
Nginx 根据请求的 URI 匹配相应的 location 块。例如如果请求的是 /doc/sseNginx 将匹配包含proxy_pass和 proxy_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/sseNginx 将请求转发到 https://doc.example.com/sse。
第五步设置请求头部
重点来了在将请求转发给后端服务之前Nginx 将根据 proxy_set_header 指令设置的值来修改请求头部。在这个过程中Nginx 会将 Host 头部设置为客户端请求中的 Host 头部的值而不是 proxy_pass 中指定的后端服务的域名。 也就是说我们请求的地址经历了以下的变化
A.example.com/doc/ssedoc.example.com/sseA.example.com/sse由proxy_set_header执行
那么相当于发生了1次不受 Nginx 管控的重定向。
正确答案
最精简的完整配置如下
location /doc/sse { proxy_pass https://doc.example.com/sse; # Disable buffering for SSEproxy_buffering off;}这里可能有的同学会好奇为什么一定要关闭代理缓存呢如果不关闭会怎么样呢下面我们来简单讲讲
为什么要关闭代理缓存
对于(SSE)来说关闭代理缓冲非常重要原因主要在于SSE的工作机制和数据流的特性。
SSE工作机制 SSE允许服务器通过一个持久的HTTP连接向客户端实时推送数据。服务器发送的数据流是一个持续的过程不是一次性完成的。代理缓冲的影响 如果代理服务器对传入的响应进行缓冲它可能会等待缓冲区填满或达到某个特定的数据量后才将数据一次性发送给客户端。这样做的结果是客户端不能实时接收到服务器推送的数据从而破坏了SSE的实时性。实时性要求 SSE的主要用途是为了实现实时通信。如果代理服务器对数据进行缓冲则实时通信的效果会被大大降低因为客户端接收数据的速度会受到影响。连接保持 除了实时性之外SSE连接需要保持打开状态以便服务器可以持续发送数据。如果代理服务器对连接进行了不当的处理例如由于长时间不活动而关闭连接这也可能干扰SSE的正常工作。
因此对于SSE来说关闭代理服务器的响应缓冲是确保数据能够及时、连续地发送给客户端的关键。这样可以保持数据流的连续性确保客户端能够实时接收到服务器端发送的每一条消息。