SpringBoot向RabbitMQ推送HttpServletRequest遇转换异常的解决问询
问题分析
HttpServletRequest是Servlet容器管理的请求上下文对象,内部包含大量与当前请求绑定的资源(如输入流、连接状态、容器内部引用等),这些字段要么不可序列化,要么存在循环引用,Jackson无法将其直接序列化为JSON,因此抛出MessageConversionException。
解决方案
不要直接发送HttpServletRequest,而是提取业务所需的关键信息封装成自定义DTO,仅将必要的请求上下文数据发送到RabbitMQ。
步骤1:定义请求上下文DTO
创建专门用于传递请求关键信息的DTO,包含租户标识、安全令牌、业务参数等你需要的字段:
import java.util.Map; public class RequestContextDTO { private String tenantId; private String accessToken; private String fileName; private Map<String, String> requestHeaders; // 按需实现Getter、Setter、构造方法 }
步骤2:修改控制器,提取请求信息并封装DTO
在控制器中从HttpServletRequest里提取所需字段,封装到自定义DTO后再发送:
@PostMapping("/createRequestQueue") public ResponseEntity<String> pushRequesttoQueue(HttpServletRequest request) { try { RequestContextDTO contextDTO = new RequestContextDTO(); // 提取租户标识 contextDTO.setTenantId(request.getHeader("X-Tenant-Identifier")); // 提取Bearer令牌 String authHeader = request.getHeader("Authorization"); if (authHeader != null && authHeader.startsWith("Bearer ")) { contextDTO.setAccessToken(authHeader.substring(7)); } // 提取业务参数(示例为文件名,根据实际需求调整) contextDTO.setFileName(request.getParameter("fileName")); // 可选:提取需要的请求头集合 // Map<String, String> headers = Collections.list(request.getHeaderNames()) // .stream().collect(Collectors.toMap(h -> h, request::getHeader)); // contextDTO.setRequestHeaders(headers); rabbitMQSender.send(contextDTO); } catch (Exception ex) { ex.printStackTrace(); } return ResponseEntity.ok("Request received successfully"); }
步骤3:调整生产者发送方法
发送自定义DTO(和普通对象发送逻辑一致,确保DTO为可序列化的纯POJO即可):
public void send(RequestContextDTO requestContext) { try { rabbitTemplate.convertAndSend(exchange, engRoutingkey, requestContext); } catch(Exception ex) { ex.printStackTrace(); } }
步骤4:修改消费者接收逻辑
消费者直接接收自定义的RequestContextDTO,使用其中的信息处理业务:
@RabbitListener(queues = "${spring.rabbitmq.requestqueue}") public void receivedMessage(RequestContextDTO requestDto) { logger.info("Request Received is.. " + requestDto.getFileName()); logger.debug("baseUrl to access file-service: " + baseUrl); HttpHeaders headers = new HttpHeaders(); headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); headers.setContentType(MediaType.APPLICATION_JSON); headers.add("X-Tenant-Identifier", requestDto.getTenantId()); headers.set("Authorization", "Bearer " + requestDto.getAccessToken()); if (logic) { String url = baseUrl + "/processFile"; // 基于上下文DTO构建业务请求DTO(按需调整) RequestDTO businessRequest = new RequestDTO(); businessRequest.setFileName(requestDto.getFileName()); HttpEntity<RequestDTO> requestEntity = new HttpEntity<>(businessRequest, headers); ResponseEntity<ResponseDTO> resp = restTemplate.postForEntity(url, requestEntity, ResponseDTO.class); logger.debug("Response:" + resp); if (resp.getStatusCode() != HttpStatus.OK) { logger.debug("Error occurred processing request:" + requestDto.getFileName()); } } }
关键说明
- 仅传递业务必需的最小数据集,减少MQ消息体积和序列化复杂度。
- 自定义DTO必须是纯POJO,不能包含容器相关的引用,确保Jackson可以正常完成序列化/反序列化。
内容的提问来源于stack exchange,提问作者Jaighanesh S
相关产品推荐
相关产品推荐

