如何将GlobalFilter中的自定义对象传递至Spring WebFlux控制器?
问题原因与解决方案
情况1:控制器属于Spring Cloud Gateway自身
你的代码逻辑本身没问题,但大概率是GlobalFilter的执行顺序导致过滤器在控制器之后运行,属性还未存入就进入了控制器处理流程。
修复步骤:
- 给GlobalFilter指定优先级,确保它在请求到达控制器前执行。可通过实现
Ordered接口或添加@Order注解设置顺序,数值越小优先级越高。 - 确保
MyCustomObject类具备基础的getter/setter方法(可通过Lombok的@Data注解简化)。
示例代码:
GlobalFilter实现(带优先级):
import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @Component public class CustomGlobalFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { MyCustomObject obj = new MyCustomObject(); obj.setSomeField("test value"); // 存入ServerWebExchange属性 exchange.getAttributes().put("MyObject", obj); return chain.filter(exchange); } @Override public int getOrder() { // 设置比默认请求处理过滤器更高的优先级 return Ordered.HIGHEST_PRECEDENCE + 10; } }
网关内部控制器:
import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.server.ServerWebExchange; @RestController public class GatewayController { @GetMapping("/test") public ResponseEntity<String> getSomething(ServerWebExchange exchange) { MyCustomObject obj = exchange.getAttribute("MyObject"); if (obj != null) { return ResponseEntity.ok("获取到对象:" + obj.getSomeField()); } return ResponseEntity.badRequest().body("未获取到对象"); } }
情况2:控制器属于下游业务服务
网关的ServerWebExchange与下游服务的ServerWebExchange是完全独立的实例,无法直接共享内存中的对象。此时需要通过HTTP请求头或请求参数将对象信息传递给下游服务。
方案:将对象序列化为JSON存入请求头,下游解析
网关GlobalFilter代码:
import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @Component public class CustomGlobalFilter implements GlobalFilter, Ordered { private final ObjectMapper objectMapper; // 注入Jackson序列化工具 public CustomGlobalFilter(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { try { MyCustomObject obj = new MyCustomObject(); obj.setSomeField("downstream test"); // 将对象序列化为JSON字符串 String objJson = objectMapper.writeValueAsString(obj); // 添加到请求头,注意头名称符合HTTP规范 exchange.getRequest().mutate() .header("X-Custom-Object", objJson) .build(); } catch (Exception e) { e.printStackTrace(); } return chain.filter(exchange); } @Override public int getOrder() { // 确保在路由转发前执行 return Ordered.HIGHEST_PRECEDENCE + 10; } }
下游服务控制器代码:
import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RestController; @RestController public class DownstreamController { private final ObjectMapper objectMapper; public DownstreamController(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @GetMapping("/downstream-test") public ResponseEntity<String> getSomething(@RequestHeader("X-Custom-Object") String objJson) { try { // 将JSON字符串反序列化为自定义对象 MyCustomObject obj = objectMapper.readValue(objJson, MyCustomObject.class); return ResponseEntity.ok("下游获取到对象:" + obj.getSomeField()); } catch (Exception e) { e.printStackTrace(); return ResponseEntity.badRequest().body("解析对象失败"); } } }
注意事项:
- 若自定义对象体积较大,不建议用请求头传递(HTTP头存在大小限制),可改用分布式缓存(如Redis)存储对象,将缓存Key通过请求头传递给下游服务,下游根据Key从缓存获取。
MyCustomObject类需保证可序列化,可通过Lombok的@Data、@NoArgsConstructor注解快速生成必要方法。
内容的提问来源于stack exchange,提问作者Akshay
相关产品推荐
相关产品推荐

