Spring Boot 內置反向代理(Undertow Proxy)高可用配置

引言

在微服務架構中,反向代理是一個不可或缺的組件,它負責請求轉發、負載均衡、安全過濾等關鍵功能。

通常我們會選擇 Nginx、HAProxy 等專業反向代理組件,但在某些場景下,使用 Spring Boot 內置的反向代理功能可以簡化架構,減少運維復雜度。

本文將介紹如何利用 Undertow 服務器的反向代理能力,實現高可用的反向代理配置。

Undertow 簡介

Undertow 是一個采用 Java 開發的靈活的高性能 Web 服務器,提供基于 NIO 的阻塞和非阻塞 API。

作為 Spring Boot 支持的內嵌式服務器之一,它具有以下特點:

輕量級:核心僅依賴于 JBoss Logging 和 xnio
高性能:在多核系統上表現優異
內置反向代理:支持 HTTP、HTTPS、HTTP/2 代理
可擴展:通過 Handler 鏈模式支持靈活擴展

為什么選擇 Undertow 內置反向代理

在某些場景下,使用 Undertow 內置的反向代理功能比獨立部署 Nginx 等代理服務器更有優勢:

1. 簡化架構:減少額外組件,降低部署復雜度
2. 統一技術棧:全 Java 技術棧,便于開發團隊維護
3. 配置靈活:可通過代碼動態調整代理規則
4. 節約資源:適合資源有限的環境,如邊緣計算場景
5. 集成監控:與 Spring Boot 的監控體系無縫集成

基礎配置

步驟 1:添加 Undertow 依賴

首先,確保 Spring Boot 項目使用 Undertow 作為嵌入式服務器:

<?xml?version="1.0"?encoding="UTF-8"?>
<project?xmlns="http://maven.apache.org/POM/4.0.0"?xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0?https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.4.5</version><relativePath/></parent><groupId>demo</groupId><artifactId>springboot-undertow-proxy</artifactId><version>0.0.1-SNAPSHOT</version><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-undertow</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.32</version><scope>provided</scope></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>21</source><target>21</target><encoding>utf-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>3.2.0</version><executions><execution><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>

步驟 2:創建 Undertow 配置類

package?com.example.config;import?io.undertow.Handlers;
import?io.undertow.server.HttpHandler;
import?io.undertow.server.handlers.PathHandler;
import?io.undertow.server.handlers.RequestLimitingHandler;
import?io.undertow.server.handlers.ResponseCodeHandler;
import?io.undertow.server.handlers.proxy.LoadBalancingProxyClient;
import?io.undertow.server.handlers.proxy.ProxyHandler;
import?io.undertow.util.HeaderMap;
import?io.undertow.util.HttpString;
import?org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import?org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import?org.springframework.boot.web.server.WebServerFactoryCustomizer;
import?org.springframework.context.annotation.Bean;
import?org.springframework.context.annotation.Configuration;
import?org.xnio.OptionMap;import?java.net.URI;@Configuration
public?class?UndertowProxyConfig?{@Bean@ConditionalOnProperty(name?=?"user.enabled",?havingValue?=?"false",?matchIfMissing?=?true)public?WebServerFactoryCustomizer<UndertowServletWebServerFactory>?undertowProxyCustomizer()?{return?factory?->?factory.addDeploymentInfoCustomizers(deploymentInfo?->?{deploymentInfo.addInitialHandlerChainWrapper(handler?->?{PathHandler?pathHandler?=?Handlers.path(handler);//?配置代理路由HttpHandler?handler1?=?createProxyClient("http://127.0.0.1:8081/user");HttpHandler?handler2?=?createProxyClient("http://127.0.0.2:8081/user/users2");handler1?=?secureProxyHandler(handler1);handler1?=?createRateLimitingHandler(handler1);//?添加路由規則pathHandler.addPrefixPath("/user",?handler1);pathHandler.addPrefixPath("/user/users2",?handler2);return?pathHandler;});});}private?HttpHandler?createProxyClient(String?targetUrl)?{try?{URI?uri?=?new?URI(targetUrl);LoadBalancingProxyClient?proxyClient?=?new?LoadBalancingProxyClient();proxyClient.addHost(uri);proxyClient.setConnectionsPerThread(20).setMaxQueueSize(10).setSoftMaxConnectionsPerThread(20).setProblemServerRetry(5).setTtl(30000);return?ProxyHandler.builder().setProxyClient(proxyClient).setMaxRequestTime(30000).setRewriteHostHeader(false).setReuseXForwarded(true).build();}?catch?(Exception?e)?{throw?new?RuntimeException("創建代理客戶端失敗",?e);}}private?HttpHandler?secureProxyHandler(HttpHandler?proxyHandler)?{return?exchange?->?{//?移除敏感頭部HeaderMap?headers?=?exchange.getRequestHeaders();headers.remove("X-Forwarded-Server");//?添加安全頭部exchange.getResponseHeaders().add(new?HttpString("X-XSS-Protection"),?"1;?mode=block");exchange.getResponseHeaders().add(new?HttpString("X-Content-Type-Options"),?"nosniff");exchange.getResponseHeaders().add(new?HttpString("X-Frame-Options"),?"DENY");//?添加代理信息headers.add(new?HttpString("X-Forwarded-For"),?exchange.getSourceAddress().getAddress().getHostAddress());headers.add(new?HttpString("X-Forwarded-Proto"),?exchange.getRequestScheme());headers.add(new?HttpString("X-Forwarded-Host"),?exchange.getHostName());proxyHandler.handleRequest(exchange);};}private?HttpHandler?createRateLimitingHandler(HttpHandler?next)?{//?根據實際情況調整return?new?RequestLimitingHandler(1,1,next);}}

高可用配置

要實現真正的高可用反向代理,需要考慮以下幾個關鍵方面:

1. 負載均衡策略

Undertow 提供多種負載均衡策略,可以根據需求選擇:

@Bean
public?LoadBalancingProxyClient?loadBalancingProxyClient()?{LoadBalancingProxyClient?loadBalancer?=?new?LoadBalancingProxyClient();//?配置負載均衡策略loadBalancer.setRouteParsingStrategy(RouteParsingStrategy.RANKED);loadBalancer.setConnectionsPerThread(20);//?添加后端服務器loadBalancer.addHost(new?URI("http://backend1:8080"));loadBalancer.addHost(new?URI("http://backend2:8080"));loadBalancer.addHost(new?URI("http://backend3:8080"));//?設置會話親和性(可選)loadBalancer.addSessionCookieName("JSESSIONID");return?loadBalancer;
}

2. 健康檢查與自動故障轉移

實現定期健康檢查,自動剔除不健康節點:

package?com.example.config;import?io.undertow.server.handlers.proxy.LoadBalancingProxyClient;
import?lombok.Data;
import?lombok.extern.slf4j.Slf4j;
import?org.springframework.beans.factory.annotation.Value;
import?org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import?org.springframework.http.ResponseEntity;
import?org.springframework.scheduling.annotation.Scheduled;
import?org.springframework.stereotype.Component;
import?org.springframework.web.client.RestTemplate;import?java.net.URI;
import?java.net.URISyntaxException;
import?java.util.Arrays;
import?java.util.List;
import?java.util.stream.Collectors;@Component
@ConditionalOnProperty(name?=?"user.enabled",?havingValue?=?"false",?matchIfMissing?=?true)
@Slf4j
public?class?BackendHealthMonitor?{private?final?LoadBalancingProxyClient?loadBalancer;private?final?List<URI>?backendServers;private?final?RestTemplate?restTemplate;public?BackendHealthMonitor(@Value("#{'${user.backends}'.split(',')}")?String[]?backends,LoadBalancingProxyClient?loadBalancer)?throws?URISyntaxException?{this.loadBalancer?=?loadBalancer;this.restTemplate?=?new?RestTemplate();this.backendServers?=?Arrays.stream(backends).map(url?->?{try?{return?new?URI(url);}?catch?(URISyntaxException?e)?{throw?new?RuntimeException(e);}}).collect(Collectors.toList());}@Scheduled(fixedDelay?=?10000)?//?每10秒檢查一次public?void?checkBackendHealth()?{for?(URI?server?:?backendServers)?{try?{String?healthUrl?=?server.getScheme()?+?"://"?+?server.getHost()?+?":"?+?server.getPort()?+?"/health";ResponseEntity<String>?response?=?restTemplate.getForEntity(healthUrl,?String.class);if?(response.getStatusCode().is2xxSuccessful())?{loadBalancer.addHost(server);log.info("后端服務?{}?狀態正常,已添加到負載均衡",?server);}?else?{//?服務不健康,從負載均衡器中移除loadBalancer.removeHost(server);log.warn("后端服務?{}?狀態異常,已從負載均衡中移除",?server);}}?catch?(Exception?e)?{//?連接異常,從負載均衡器中移除loadBalancer.removeHost(server);log.error("后端服務?{}?連接異常:?{}",?server,?e.getMessage());}}}
}

3. 集群高可用

為確保被代理服務的高可用,可配置多個代理實例:

user:backends:?"http://127.0.0.1:8081,http://127.0.0.2:8081"

性能優化

要獲得最佳性能,需要調整 Undertow 的相關參數(需要根據項目實際情況進行測試調整):

server:undertow:threads:?io:?8??????????????????????#?IO線程數,建議設置為CPU核心數worker:?64?????????????????#?工作線程數,IO線程數的8倍buffer-size:?16384???????????#?緩沖區大小direct-buffers:?true?????????#?使用直接緩沖區max-http-post-size:?10485760?#?最大POST大小max-parameters:?2000?????????#?最大參數數量max-headers:?200?????????????#?最大請求頭數量max-cookies:?200?????????????#?最大Cookie數量

連接池優化

@Bean
public?UndertowServletWebServerFactory?undertowFactory()?{UndertowServletWebServerFactory?factory?=?new?UndertowServletWebServerFactory();factory.addBuilderCustomizers(builder?->?{builder.setSocketOption(Options.KEEP_ALIVE,?true).setSocketOption(Options.TCP_NODELAY,?true).setSocketOption(Options.REUSE_ADDRESSES,?true).setSocketOption(Options.BACKLOG,?10000).setServerOption(UndertowOptions.MAX_ENTITY_SIZE,?16?*?1024?*?1024L).setServerOption(UndertowOptions.IDLE_TIMEOUT,?60?*?1000).setServerOption(UndertowOptions.REQUEST_PARSE_TIMEOUT,?30?*?1000).setServerOption(UndertowOptions.NO_REQUEST_TIMEOUT,?60?*?1000).setServerOption(UndertowOptions.MAX_CONCURRENT_REQUESTS_PER_CONNECTION,?200);});return?factory;
}

安全強化

反向代理需要考慮安全性,可以添加以下配置:

1. 請求頭過濾與重寫

private?HttpHandler?secureProxyHandler(HttpHandler?proxyHandler)?{return?exchange?->?{//?移除敏感頭部HeaderMap?headers?=?exchange.getRequestHeaders();headers.remove("X-Forwarded-Server");//?添加安全頭部exchange.getResponseHeaders().add(new?HttpString("X-XSS-Protection"),?"1;?mode=block");exchange.getResponseHeaders().add(new?HttpString("X-Content-Type-Options"),?"nosniff");exchange.getResponseHeaders().add(new?HttpString("X-Frame-Options"),?"DENY");//?添加代理信息headers.add(new?HttpString("X-Forwarded-For"),?exchange.getSourceAddress().getAddress().getHostAddress());headers.add(new?HttpString("X-Forwarded-Proto"),?exchange.getRequestScheme());headers.add(new?HttpString("X-Forwarded-Host"),?exchange.getHostName());proxyHandler.handleRequest(exchange);};
}

2. 請求限流

private?HttpHandler?createRateLimitingHandler(HttpHandler?next)?{return?new?RequestLimitingHandler(100,next);
}

實際案例:某系統 API 網關

以一個電商系統為例,展示 Undertow 反向代理的實際應用:

package?com.example.config;import?io.undertow.Handlers;
import?io.undertow.server.HttpHandler;
import?io.undertow.server.handlers.PathHandler;
import?io.undertow.server.handlers.proxy.LoadBalancingProxyClient;
import?io.undertow.server.handlers.proxy.ProxyHandler;
import?org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import?org.springframework.boot.web.server.WebServerFactoryCustomizer;
import?org.springframework.context.annotation.Bean;
import?org.springframework.context.annotation.Configuration;import?java.net.URI;@Configuration
public?class?EcommerceProxyConfig?{@Beanpublic?WebServerFactoryCustomizer<UndertowServletWebServerFactory>?ecommerceProxyCustomizer()?{return?factory?->?factory.addDeploymentInfoCustomizers(deploymentInfo?->?{deploymentInfo.addInitialHandlerChainWrapper(handler?->?{PathHandler?pathHandler?=?Handlers.path(handler);try?{//?用戶服務代理LoadBalancingProxyClient?userServiceClient?=?new?LoadBalancingProxyClient();userServiceClient.addHost(new?URI("http://user-service-1:8080/api/users"));userServiceClient.addHost(new?URI("http://user-service-2:8080/api/users"));//?商品服務代理LoadBalancingProxyClient?productServiceClient?=?new?LoadBalancingProxyClient();productServiceClient.addHost(new?URI("http://product-service-1:8080/api/products"));productServiceClient.addHost(new?URI("http://product-service-2:8080/api/products"));//?訂單服務代理LoadBalancingProxyClient?orderServiceClient?=?new?LoadBalancingProxyClient();orderServiceClient.addHost(new?URI("http://order-service-1:8080/api/orders"));orderServiceClient.addHost(new?URI("http://order-service-2:8080/api/orders"));//?路由規則pathHandler.addPrefixPath("/api/users",?createProxyHandler(userServiceClient));pathHandler.addPrefixPath("/api/products",?createProxyHandler(productServiceClient));pathHandler.addPrefixPath("/api/orders",?createProxyHandler(orderServiceClient));return?pathHandler;}catch?(Exception?e){throw?new?RuntimeException(e);}});});}private?HttpHandler?createProxyHandler(LoadBalancingProxyClient?client)?{return?ProxyHandler.builder().setProxyClient(client).setMaxRequestTime(30000).setRewriteHostHeader(true).build();}
}

總結

Spring Boot 內置的 Undertow 反向代理功能為微服務架構提供了一種輕量級的代理解決方案。

雖然功能上可能不如專業的反向代理服務器(如 Nginx)那么豐富,但在特定場景下,尤其是希望簡化架構、統一技術棧的情況下,可以作為一種備選方案。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/86984.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/86984.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/86984.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ClickHouse 部署

Docker 部署 1、拉取鏡像 docker pull clickhouse/clickhouse-server:latest單機版本部署 編寫docker-compose.yml version: 3services:clickhouse-server:image: clickhouse/clickhouse-server:22.12container_name: clickhouse-serverports:- "8123:8123"ulimit…

Fiddler中文版抓包工具如何幫助前端開發者高效調試

前端開發早已不再是“寫好頁面就完事”的工作。隨著業務復雜度提升&#xff0c;前端開發者需要直面接口聯調、性能優化、跨域排查、HTTPS調試等一系列和網絡請求緊密相關的任務。抓包工具成為這些環節中不可替代的得力助手&#xff0c;而 Fiddler抓包工具 因其全面的功能和靈活…

WTL 之trunk技術學習

相比于MFC的消息機制&#xff0c;WTL/ATL的實現更加優雅。后者將win32 API與面向對象技術完美地結合起來&#xff0c;去掉了龐雜的MFC依賴&#xff0c;生成的軟件體積更小&#xff0c;運行速度更快。在其中&#xff0c;如何將窗口函數轉變為對窗口對象成員函數的調用&#xff0…

Linux——11.軟件安裝與包管理

Linux 與 Windows 系統在軟件安裝方式上的差異 Linux: Linux 通過 包管理系統(如 Debian 的 apt、Red Hat 的 yum/dnf)將軟件打包為二進制安裝包(如 .deb、.rpm),每個包包含程序文件、依賴關系和元數據。包管理系統負責統一管理軟件的安裝、更新、卸載,并自動處理依賴關…

無人機用shell遠程登錄機載電腦,每次需要環境配置原因

原因&#xff1a; 終端分為“登錄 shell”和“非登錄 shell”&#xff1a; - 登錄 shell&#xff08;如開機登錄、遠程 SSH 連接&#xff09;會加載 .profile 或 .bash_profile 。 - 非登錄 shell&#xff08;如打開新終端窗口&#xff09;會加載 .bashrc 。 - 如果環境變量…

HarmonyOS5 折疊屏適配測試:驗證APP在展開/折疊狀態下的界面自適應,以及會出現的問題

以下是HarmonyOS5折疊屏應用在展開/折疊狀態下的UI自適應測試方案及技術實現要點&#xff1a; 一、核心測試維度 ?狀態連續性驗證? 頁面滾動位置保持&#xff08;需通過display.on(foldStatusChange)監聽狀態并保存/恢復滾動位置&#xff09;輸入內容保留&#xff08;使用…

Introduction to Software Engineering(TE)

Program Design Language 也稱為&#xff1a;偽代碼語言&#xff08;Pseudo-code Language&#xff09; PDL 的同類&#xff08;或相關替代&#xff09; 名稱簡介是否代碼結構化流程圖 (Flowchart)用圖形方式描述處理邏輯?偽代碼 (Pseudo-code)通用術語&#xff0c;PDL就是…

DM8數據庫入門到熟練

1、部署 1.1、下載 用戶在安裝 DM 數據庫之前需要檢查或修改操作系統的配置&#xff0c;以保證 DM 數據庫能夠正確安裝和運行。 操作系統CPU數據庫CentOS7x86_64dm8_20250506_x86_rh7_64.zip 1.2、新建 dmdba 用戶 安裝前必須創建 dmdba 用戶&#xff0c;禁止使用 root 用戶…

VUE3入門很簡單(2)--- 計算屬性

前言 重要提示&#xff1a;文章只適合初學者&#xff0c;不適合專家&#xff01;&#xff01;&#xff01; 為什么需要計算屬性&#xff1f; 想象你在開發一個購物車功能。當用戶選擇商品時&#xff0c;你需要&#xff1a; 計算商品總價根據折扣碼調整價格自動更新免運費狀…

IPV6概述

1. 定義 IPv6&#xff08;Internet Protocol version 6&#xff09;是互聯網協議的第六版&#xff0c;設計用于替代現有的 IPv4 協議。IPv6 提供了更大的地址空間、增強的路由效率、更好的安全性以及自動配置功能&#xff0c;以滿足現代網絡的需求。 1.1 地址空間 IPv6 地址長…

量子機器學習:AI算力突破量子優勢臨界點?

前言 前些天發現了一個巨牛的人工智能免費學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到網站 以下是為您撰寫的第六篇CSDN深度技術解析文章&#xff0c;圍繞前沿命題 《量子機器學習&#xff1a;AI算力突破量子優勢臨界點&…

Kerberos 深入詳解:原理、認證流程與應用場景

目錄 什么是 KerberosKerberos 原理解析Kerberos 認證完整流程Kerberos 應用場景常見問題與最佳實踐參考資料 什么是 Kerberos Kerberos 是一種廣泛應用于計算機網絡中的身份認證協議&#xff0c;它基于對稱密鑰加密思想&#xff0c;核心目標是在不安全的網絡中實現安全的身份…

mac安裝node 實測可行

進入nodejs官網&#xff0c;選擇mac,選擇安裝方式&#xff0c;選擇版本即可獲得安裝命令 直接執行即可 具體腳本 # Download and install nvm: curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash# in lieu of restarting the shell \. "…

山石網科談平凡對話中的咒語——提示詞注入攻擊與防御

現場 2026 年 4 月 25 日上午&#xff0c;A市 初春的街道&#xff0c;陽光普照&#xff0c;鳥語花香&#xff0c;V 君中午要與一個重要的客戶見面&#xff0c; 特意預約了人氣正旺的星際咖啡館&#xff0c;他家主打未來科幻風&#xff0c;之前去過幾次&#xff0c; 服務周到、…

SpringMVC系列(五)(響應實驗以及Restful架構風格(上))

0 引言 作者正在學習SpringMVC相關內容&#xff0c;學到了一些知識&#xff0c;希望分享給需要短時間想要了解SpringMVC的讀者朋友們&#xff0c;想用通俗的語言講述其中的知識&#xff0c;希望與諸位共勉&#xff0c;共同進步&#xff01; 本系列會持續更新&#xff01;&…

Windows 環境下設置 RabbitMQ 的 consumer_timeout 參數

在 Windows 環境下設置 RabbitMQ 的 consumer_timeout 參數&#xff0c;可以通過臨時修改或永久修改兩種方式實現。以下是具體操作步驟&#xff1a; 一、臨時修改&#xff08;無需重啟服務&#xff0c;但重啟后失效&#xff09; ?通過命令行動態設置? 打開命令提示符&#xf…

Python 中切換鏡像源

在 Python 中切換鏡像源主要涉及 pip 包管理器 和 conda 環境&#xff08;如 Anaconda、Miniconda&#xff09; 的配置。國內訪問 Python 官方源&#xff08;PyPI&#xff09;可能較慢&#xff0c;因此推薦使用國內鏡像源&#xff08;如阿里云、清華大學、豆瓣等&#xff09;。…

深入解析拓撲排序算法:從原理到C++實現

一、拓撲排序概述 拓撲排序(Topological Sorting)是對有向無環圖(Directed Acyclic Graph&#xff0c;簡稱DAG)的頂點進行排序&#xff0c;得到一個線性序列&#xff0c;使得對于圖中的任意一對頂點u和v&#xff0c;若存在一條從u到v的路徑&#xff0c;則u在排序結果中出現在v…

圖像質量對比感悟

具體任務&#xff1a; 在本次任務中&#xff0c;我需要對比兩張1080p的yuv圖片的清晰度&#xff0c;那么如何判斷呢&#xff1f;主要是進行了主觀判斷和客觀psnr的判斷。 psnr解釋&#xff1a; 定義&#xff1a; PSNR 用于衡量 兩幅圖像之間的差異&#xff08;通常是原始圖像和…

機器學習(ML)-Scikit-Learn--快速入門

專欄:機器學習 個人主頁:云端筑夢獅 一.數據集讀取方法&#xff08;常用功能用熟即可不用背下來&#xff09; 以例子代表需要的知識點和方法。 1. 導入必要的庫 from sklearn.datasets import load_iris import numpy as npload_iris()&#xff1a;用于加載鳶尾花數據集的…