引言

在微服务架构中,反向代理是一个不可或缺的组件,它负责请求转发、负载均衡、安全过滤等关键功能。

通常我们会选择 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;用于加载鸢尾花数据集的…