Skip to content

RemoveJsonAttributesResponseBody 网关过滤器工厂

概述

RemoveJsonAttributesResponseBody 是 Spring Cloud Gateway 提供的一个内置过滤器工厂,专门用于处理 JSON 响应体的属性移除。它允许开发者在网关层面对下游服务返回的 JSON 数据进行清理和过滤,移除敏感或不必要的字段。

功能特性

IMPORTANT

该过滤器主要解决了在微服务架构中,需要对下游服务返回的 JSON 响应进行字段过滤的问题,避免敏感信息暴露给客户端。

核心能力

  • 属性移除:根据指定的属性名称列表移除 JSON 中的字段
  • 层级控制:支持仅在根级别移除或递归移除所有层级的指定属性
  • 灵活配置:通过简单的 YAML 配置即可实现复杂的 JSON 转换

业务场景

在实际的微服务开发中,RemoveJsonAttributesResponseBody 过滤器常用于以下场景:

1. 数据脱敏场景

当用户服务返回用户信息时,需要移除敏感字段如密码、内部 ID 等:

2. API 版本兼容

不同版本的客户端可能需要不同的数据结构,通过过滤器移除新版本字段:

配置参数

参数类型必填说明
attribute namesString[]要移除的属性名称列表
recursiveBoolean是否递归移除,默认 false(仅根级别)

配置示例

基础配置 - 根级别移除

仅移除 JSON 根级别的指定属性:

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: user_profile_route
          uri: http://user-service
          predicates:
            - Path=/api/user/**
          filters:
            # 移除根级别的 password 和 internalId 字段
            - RemoveJsonAttributesResponseBody=password,internalId
kotlin
@Configuration
class GatewayConfig {

    @Bean
    fun userProfileRoute(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            .route("user_profile_route") { r ->
                r.path("/api/user/**")
                    .filters { f ->
                        f.filter(RemoveJsonAttributesResponseBodyGatewayFilterFactory()
                            .apply(RemoveJsonAttributesResponseBodyGatewayFilterFactory.Config()
                                .apply {
                                    // 设置要移除的属性名称
                                    attributeNames = listOf("password", "internalId")
                                    // 仅在根级别移除 (默认值)
                                    deleteRecursively = false
                                }))
                    }
                    .uri("http://user-service")
            }
            .build()
    }
}

处理效果演示

原始 JSON 响应:

json
{
  "id": 1001,
  "username": "zhangsan",
  "password": "encrypted_password_hash",
  "email": "zhangsan@example.com",
  "internalId": "internal_user_12345",
  "profile": {
    "nickname": "张三",
    "avatar": "https://example.com/avatar.jpg"
  }
}

过滤后的响应:

json
{
  "id": 1001,
  "username": "zhangsan",
  "email": "zhangsan@example.com",
  "profile": {
    "nickname": "张三",
    "avatar": "https://example.com/avatar.jpg"
  }
}

高级配置 - 递归移除

递归移除 JSON 中所有层级的指定属性:

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: product_catalog_route
          uri: http://product-service
          predicates:
            - Path=/api/products/**
          filters:
            # 递归移除所有层级的 cost 和 supplierId 字段
            - RemoveJsonAttributesResponseBody=cost,supplierId,true
kotlin
@Configuration
class ProductGatewayConfig {

    @Bean
    fun productCatalogRoute(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            .route("product_catalog_route") { r ->
                r.path("/api/products/**")
                    .filters { f ->
                        f.filter(RemoveJsonAttributesResponseBodyGatewayFilterFactory()
                            .apply(RemoveJsonAttributesResponseBodyGatewayFilterFactory.Config()
                                .apply {
                                    // 设置要移除的属性名称
                                    attributeNames = listOf("cost", "supplierId")
                                    // 递归移除所有层级
                                    deleteRecursively = true
                                }))
                    }
                    .uri("http://product-service")
            }
            .build()
    }
}

递归处理效果演示

原始 JSON 响应:

json
{
  "id": 2001,
  "name": "智能手机",
  "price": 2999.0,
  "cost": 1800.0,
  "supplierId": "SUPPLIER_001",
  "variants": [
    {
      "id": 2001001,
      "color": "黑色",
      "storage": "128GB",
      "cost": 1750.0,
      "supplierId": "SUPPLIER_001"
    },
    {
      "id": 2001002,
      "color": "白色",
      "storage": "256GB",
      "cost": 1850.0,
      "supplierId": "SUPPLIER_002"
    }
  ]
}

递归过滤后的响应:

json
{
  "id": 2001,
  "name": "智能手机",
  "price": 2999.0,
  "variants": [
    {
      "id": 2001001,
      "color": "黑色",
      "storage": "128GB"
    },
    {
      "id": 2001002,
      "color": "白色",
      "storage": "256GB"
    }
  ]
}

实际业务应用案例

案例 1:电商平台商品信息过滤

在电商平台中,商品服务可能包含成本价格、供应商信息等内部数据,这些信息不应该暴露给前端客户:

kotlin
@Configuration
class ECommerceGatewayConfig {

    @Bean
    fun ecommerceRoutes(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            // 商品列表路由 - 移除成本相关信息
            .route("product_list") { r ->
                r.path("/api/v1/products")
                    .filters { f ->
                        f.removeJsonAttributesResponseBody("cost", "supplierPrice", "margin", true)
                    }
                    .uri("http://product-service")
            }
            // 用户信息路由 - 移除敏感信息
            .route("user_info") { r ->
                r.path("/api/v1/user/profile")
                    .filters { f ->
                        f.removeJsonAttributesResponseBody("password", "salt", "internalNotes")
                    }
                    .uri("http://user-service")
            }
            .build()
    }
}

案例 2:多租户 SaaS 平台数据隔离

在多租户环境中,需要根据租户权限过滤不同的数据字段:

kotlin
@Component
class TenantDataFilterConfig {

    @Bean
    fun tenantSpecificRoutes(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            // 基础租户 - 移除高级功能字段
            .route("basic_tenant") { r ->
                r.path("/api/data/**")
                    .and().header("X-Tenant-Type", "BASIC")
                    .filters { f ->
                        f.removeJsonAttributesResponseBody(
                            "advancedAnalytics",
                            "premiumFeatures",
                            "customReports",
                            true
                        )
                    }
                    .uri("http://data-service")
            }
            // 高级租户 - 保留所有字段
            .route("premium_tenant") { r ->
                r.path("/api/data/**")
                    .and().header("X-Tenant-Type", "PREMIUM")
                    .uri("http://data-service")
            }
            .build()
    }
}

工作原理

性能考虑

WARNING

使用该过滤器会增加网关的响应处理时间,因为需要解析和重新序列化 JSON 内容。

性能优化建议

  1. 合理使用递归模式:仅在必要时使用递归移除,根级别移除性能更好
  2. 控制 JSON 大小:对于大型 JSON 响应,考虑在服务端进行字段筛选
  3. 缓存策略:对于静态或变化较少的响应,可以结合缓存过滤器使用

注意事项

TIP

该过滤器只能处理有效的 JSON 格式响应体,对于非 JSON 内容会跳过处理。

CAUTION

移除属性操作是不可逆的,请确保移除的字段确实不被客户端需要。

最佳实践

  1. 明确字段用途:在移除字段前,确认这些字段不会被前端或下游系统使用
  2. 版本兼容性:考虑 API 版本兼容性,避免破坏现有客户端
  3. 监控和日志:添加适当的监控来跟踪过滤器的使用情况
  4. 测试覆盖:编写充分的测试来验证过滤器的行为

与其他过滤器的组合使用

RemoveJsonAttributesResponseBody 可以与其他网关过滤器组合使用,实现更复杂的功能:

kotlin
@Configuration
class CompositeFilterConfig {

    @Bean
    fun secureApiRoute(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes()
            .route("secure_api") { r ->
                r.path("/api/secure/**")
                    .filters { f ->
                        f.requestRateLimiter { config ->
                            // 限流配置
                            config.rateLimiter = redisRateLimiter()
                            config.keyResolver = ipKeyResolver()
                        }
                        .addRequestHeader("X-Gateway-Filter", "Applied")
                        .removeJsonAttributesResponseBody("internalId", "debug", true)
                        .addResponseHeader("X-Filtered", "true")
                    }
                    .uri("http://secure-service")
            }
            .build()
    }
}

通过合理使用 RemoveJsonAttributesResponseBody 过滤器,可以在网关层面实现有效的数据脱敏和字段过滤,提高 API 的安全性和数据传输效率。