Appearance
FallbackHeaders Gateway Filter Factory
概述
FallbackHeaders 专门用于在熔断器降级场景中向转发请求添加异常详细信息的请求头。当后端服务出现故障触发熔断器时,该过滤器能够将异常信息传递给降级服务,帮助降级服务更好地处理异常情况。
解决的问题
在微服务架构中,服务之间的调用链路复杂,当某个服务出现故障时,如果没有合适的降级机制,可能会导致整个调用链路的雪崩效应。Spring Cloud Gateway 通过集成 Spring Cloud CircuitBreaker 提供熔断降级功能,但降级服务往往需要了解原始请求失败的具体原因才能提供更好的用户体验。
FallbackHeaders 过滤器解决了以下关键问题:
- 异常信息传递:将原始服务的异常类型和消息传递给降级服务
- 根因追踪:提供异常的根本原因信息,便于问题排查
- 降级服务优化:让降级服务能够根据不同的异常类型提供差异化的降级响应
工作原理
配置示例
基础配置
yaml
spring:
cloud:
gateway:
routes:
# 主要路由配置 - 包含熔断器
- id: ingredients
uri: lb://ingredients
predicates:
- Path=/ingredients/**
filters:
- name: CircuitBreaker
args:
name: fetchIngredients
fallbackUri: forward:/fallback
# 降级路由配置 - 使用 FallbackHeaders
- id: ingredients-fallback
uri: http://localhost:9994
predicates:
- Path=/fallback
filters:
- name: FallbackHeaders
args:
executionExceptionTypeHeaderName: Test-Headerkotlin
@Configuration
class GatewayConfig {
@Bean
fun customRouteLocator(builder: RouteLocatorBuilder): RouteLocator {
return builder.routes()
// 主要路由 - 包含熔断器
.route("ingredients") { r ->
r.path("/ingredients/**")
.filters { f ->
f.circuitBreaker { config ->
config.name = "fetchIngredients"
config.fallbackUri = "forward:/fallback"
}
}
.uri("lb://ingredients")
}
// 降级路由 - 使用 FallbackHeaders
.route("ingredients-fallback") { r ->
r.path("/fallback")
.filters { f ->
f.fallbackHeaders { config ->
config.executionExceptionTypeHeaderName = "Custom-Exception-Type"
config.executionExceptionMessageHeaderName = "Custom-Exception-Message"
}
}
.uri("http://localhost:9994")
}
.build()
}
}自定义头部名称配置
yaml
spring:
cloud:
gateway:
routes:
- id: order-fallback
uri: http://localhost:8081
predicates:
- Path=/order-fallback
filters:
- name: FallbackHeaders
args:
# 自定义异常类型头部名称
executionExceptionTypeHeaderName: "X-Order-Exception-Type"
# 自定义异常消息头部名称
executionExceptionMessageHeaderName: "X-Order-Exception-Message"
# 自定义根因异常类型头部名称
rootCauseExceptionTypeHeaderName: "X-Order-Root-Cause-Type"
# 自定义根因异常消息头部名称
rootCauseExceptionMessageHeaderName: "X-Order-Root-Cause-Message"配置参数详解
| 参数名称 | 默认值 | 说明 |
|---|---|---|
executionExceptionTypeHeaderName | "Execution-Exception-Type" | 执行异常类型的头部名称 |
executionExceptionMessageHeaderName | "Execution-Exception-Message" | 执行异常消息的头部名称 |
rootCauseExceptionTypeHeaderName | "Root-Cause-Exception-Type" | 根因异常类型的头部名称 |
rootCauseExceptionMessageHeaderName | "Root-Cause-Exception-Message" | 根因异常消息的头部名称 |
所有参数都是可选的。如果不指定,将使用默认的头部名称。你可以根据业务需要自定义头部名称,避免与现有头部冲突。
实际业务场景示例
场景一:电商订单服务降级
在电商系统中,当订单服务出现异常时,需要根据不同的异常类型提供不同的降级策略:
kotlin
@RestController
@RequestMapping("/order")
class OrderController {
@Autowired
private lateinit var orderService: OrderService
/**
* 创建订单接口
*/
@PostMapping("/create")
fun createOrder(@RequestBody orderRequest: OrderRequest): ResponseEntity<OrderResponse> {
return try {
val order = orderService.createOrder(orderRequest)
ResponseEntity.ok(OrderResponse.success(order))
} catch (e: Exception) {
// 这里的异常会被熔断器捕获,并通过 FallbackHeaders 传递给降级服务
throw OrderCreationException("订单创建失败", e)
}
}
}kotlin
@RestController
@RequestMapping("/fallback")
class FallbackController {
/**
* 订单服务降级处理
* 根据 FallbackHeaders 传递的异常信息提供差异化降级响应
*/
@PostMapping("/order")
fun orderFallback(
request: HttpServletRequest,
@RequestBody orderRequest: OrderRequest
): ResponseEntity<OrderResponse> {
// 获取 FallbackHeaders 添加的异常信息
val exceptionType = request.getHeader("Execution-Exception-Type")
val exceptionMessage = request.getHeader("Execution-Exception-Message")
val rootCauseType = request.getHeader("Root-Cause-Exception-Type")
val rootCauseMessage = request.getHeader("Root-Cause-Exception-Message")
// 记录异常信息用于监控和排查
log.warn("订单服务降级触发 - 异常类型: $exceptionType, 消息: $exceptionMessage")
// 根据异常类型提供差异化降级策略
return when {
exceptionType?.contains("TimeoutException") == true -> {
// 超时异常 - 提示用户稍后重试
ResponseEntity.ok(OrderResponse.fallback(
"系统繁忙,请稍后重试",
FallbackType.RETRY_LATER
))
}
exceptionType?.contains("ValidationException") == true -> {
// 验证异常 - 返回具体的验证错误信息
ResponseEntity.badRequest().body(OrderResponse.fallback(
"订单信息验证失败:$exceptionMessage",
FallbackType.VALIDATION_ERROR
))
}
exceptionType?.contains("DatabaseException") == true -> {
// 数据库异常 - 提示系统维护
ResponseEntity.ok(OrderResponse.fallback(
"系统正在维护中,请稍后重试",
FallbackType.MAINTENANCE
))
}
else -> {
// 其他异常 - 通用降级响应
ResponseEntity.ok(OrderResponse.fallback(
"服务暂时不可用,请联系客服",
FallbackType.GENERAL_ERROR
))
}
}
}
companion object {
private val log = LoggerFactory.getLogger(FallbackController::class.java)
}
}场景二:支付服务异常处理
支付服务的异常信息对于用户体验和业务决策都非常重要:
kotlin
@RestController
@RequestMapping("/payment")
class PaymentFallbackController {
@PostMapping("/process")
fun paymentFallback(
request: HttpServletRequest,
@RequestBody paymentRequest: PaymentRequest
): ResponseEntity<PaymentResponse> {
val exceptionType = request.getHeader("Execution-Exception-Type")
val exceptionMessage = request.getHeader("Execution-Exception-Message")
// 记录支付异常用于风控分析
paymentAuditService.recordPaymentFailure(
userId = paymentRequest.userId,
amount = paymentRequest.amount,
exceptionType = exceptionType,
exceptionMessage = exceptionMessage
)
return when {
exceptionType?.contains("InsufficientBalanceException") == true -> {
ResponseEntity.ok(PaymentResponse.failure(
code = "INSUFFICIENT_BALANCE",
message = "账户余额不足,请充值后重试"
))
}
exceptionType?.contains("RiskControlException") == true -> {
ResponseEntity.ok(PaymentResponse.failure(
code = "RISK_CONTROL",
message = "交易存在风险,已暂停处理"
))
}
exceptionType?.contains("NetworkException") == true -> {
ResponseEntity.ok(PaymentResponse.failure(
code = "NETWORK_ERROR",
message = "网络连接异常,请检查网络后重试"
))
}
else -> {
ResponseEntity.ok(PaymentResponse.failure(
code = "SYSTEM_ERROR",
message = "系统异常,请稍后重试"
))
}
}
}
}与其他过滤器的配合使用
与熔断器过滤器配合
yaml
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/user/**
filters:
# 1. 首先应用熔断器
- name: CircuitBreaker
args:
name: userServiceCircuitBreaker
fallbackUri: forward:/user-fallback
# 熔断器配置
failureRateThreshold: 50
slowCallRateThreshold: 50
slowCallDurationThreshold: 2s
minimumNumberOfCalls: 10
slidingWindowSize: 10
# 2. 添加请求日志
- name: RequestLogging
- id: user-fallback
uri: http://localhost:8082
predicates:
- Path=/user-fallback
filters:
# 1. 添加异常头部信息
- name: FallbackHeaders
args:
executionExceptionTypeHeaderName: "User-Exception-Type"
executionExceptionMessageHeaderName: "User-Exception-Message"
# 2. 添加降级标识头部
- name: AddRequestHeader
args:
name: X-Fallback-Reason
value: user-service-circuit-breaker
# 3. 限流保护降级服务
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 100
redis-rate-limiter.burstCapacity: 200监控和调试
启用请求日志
kotlin
@Component
class FallbackHeadersLoggingFilter : GlobalFilter, Ordered {
override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
return chain.filter(exchange).doFinally {
val request = exchange.request
val headers = request.headers
// 记录 FallbackHeaders 添加的异常信息
if (headers.containsKey("Execution-Exception-Type")) {
log.info("降级请求处理 - 路径: ${request.path}, " +
"异常类型: ${headers.getFirst("Execution-Exception-Type")}, " +
"异常消息: ${headers.getFirst("Execution-Exception-Message")}")
}
}
}
override fun getOrder(): Int = -1
companion object {
private val log = LoggerFactory.getLogger(FallbackHeadersLoggingFilter::class.java)
}
}健康检查端点
kotlin
@RestController
@RequestMapping("/actuator")
class FallbackHealthController {
@GetMapping("/fallback-stats")
fun getFallbackStats(request: HttpServletRequest): Map<String, Any> {
return mapOf(
"timestamp" to System.currentTimeMillis(),
"fallback_headers" to mapOf(
"execution_exception_type" to request.getHeader("Execution-Exception-Type"),
"execution_exception_message" to request.getHeader("Execution-Exception-Message"),
"root_cause_exception_type" to request.getHeader("Root-Cause-Exception-Type"),
"root_cause_exception_message" to request.getHeader("Root-Cause-Exception-Message")
)
)
}
}最佳实践
IMPORTANT
降级服务保护
降级服务是系统的最后一道防线,必须确保其高可用性。建议为降级服务配置独立的资源池,并设置适当的限流策略。
TIP
异常信息安全
在生产环境中,要注意异常信息的安全性。避免在异常消息中暴露敏感信息,如数据库连接信息、内部服务地址等。
WARNING
头部大小限制
HTTP 头部有大小限制,确保异常消息不会过长。建议对异常消息进行截断或编码处理。
异常信息脱敏
kotlin
@Component
class SensitiveInfoSanitizer {
private val sensitivePatterns = listOf(
"password=\\w+".toRegex(),
"token=\\w+".toRegex(),
"jdbc:mysql://[\\w.]+:\\d+".toRegex()
)
fun sanitizeExceptionMessage(message: String?): String? {
if (message == null) return null
var sanitized = message
sensitivePatterns.forEach { pattern ->
sanitized = pattern.replace(sanitized, "[REDACTED]")
}
// 限制异常消息长度
return if (sanitized.length > 200) {
sanitized.substring(0, 200) + "..."
} else {
sanitized
}
}
}常见问题解决
问题一:降级服务接收不到异常头部
原因分析:
- 路由配置错误,FallbackHeaders 过滤器未正确配置
- 降级 URI 不匹配
解决方案:
yaml
# 确保降级路由正确配置
spring:
cloud:
gateway:
routes:
- id: main-route
filters:
- name: CircuitBreaker
args:
fallbackUri: forward:/fallback # 确保与降级路由匹配
- id: fallback-route
predicates:
- Path=/fallback # 确保路径匹配
filters:
- name: FallbackHeaders # 确保过滤器正确配置问题二:异常信息丢失
原因分析:
- 异常被其他过滤器拦截并处理
- 异常信息为空或格式不正确
解决方案:
kotlin
// 自定义异常处理器确保异常信息完整
@Component
class CustomExceptionHandler : ResponseEntityExceptionHandler() {
@ExceptionHandler(Exception::class)
fun handleGenericException(e: Exception): ResponseEntity<ErrorResponse> {
// 确保异常信息被正确设置
val errorResponse = ErrorResponse(
message = e.message ?: "Unknown error",
type = e.javaClass.simpleName,
timestamp = System.currentTimeMillis()
)
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(errorResponse)
}
}总结
FallbackHeaders 过滤器工厂是 Spring Cloud Gateway 中一个强大而实用的工具,它通过将异常信息传递给降级服务,使得系统能够提供更加智能和用户友好的降级响应。
主要优势:
- 🔍 异常信息透明:完整传递异常类型和消息
- 🎯 差异化降级:支持根据异常类型定制降级策略
- 🛡️ 系统稳定性:提高整体系统的容错能力
- 📊 可观测性:便于监控和问题排查
在微服务架构中合理使用 FallbackHeaders 过滤器,能够显著提升用户体验和系统的健壮性。