Java中Supplier<ResponseEntity>强转RequestEntity报错如何获取请求信息
问题根因
你的强转逻辑必然抛出异常:入参request是Supplier<ResponseEntity>类型的函数式接口实例,你传入的是lambda表达式() -> restTemplate.exchange(...),和RequestEntity没有任何继承/实现关系,完全不属于同一类型体系,强转肯定失败。
解决方案
方案1:修改方法签名显式传递请求元数据(推荐,改造成本极低)
直接把你需要的URL、请求方法等信息作为入参传给executeRequest,不需要从Supplier中获取:
- 调整
executeRequest方法逻辑:
// 方法签名新增uri、method参数,可按需新增HttpEntity等其他请求参数 protected ResponseEntity executeRequest(Supplier<ResponseEntity> request, URI uri, HttpMethod method) { try { ResponseEntity response = request.get(); updateSessionToken(response); return response; } catch (HttpClientErrorException | HttpServerErrorException e) { // 直接用传入的参数拼接完整报错信息 String msg = String.format("WDD3D-Error in service communication, 请求地址:%s, 请求方法:%s <br>错误响应:%s", uri.toString(), method.name(), e.getResponseBodyAsString()); throw new MaestroException(msg); } }
- 调整业务调用处代码:
public void execute() { HttpHeaders headers = buildDefaultHeaders(); URI uri = UriBuilder.fromUri(wdd3dGatewayEndpoint + API_URL).build(); HttpMethod method = HttpMethod.DELETE; HttpEntity request = new HttpEntity(headers); this.executeRequest(() -> restTemplate.exchange(uri, method, request, Void.class), uri, method); }
方案2:RestTemplate拦截器全局捕获(适合调用点多的场景,无需修改业务调用代码)
如果项目中调用executeRequest的地方很多,挨个改参数成本高,可以通过RestTemplate拦截器把请求信息存入ThreadLocal,异常发生时直接读取:
- 定义请求上下文容器和拦截器:
// 请求信息存储容器 public class RequestContextHolder { private static final ThreadLocal<Map<String, String>> REQUEST_CONTEXT = new ThreadLocal<>(); public static void set(String url, String method) { Map<String, String> context = new HashMap<>(); context.put("url", url); context.put("method", method); REQUEST_CONTEXT.set(context); } public static Map<String, String> get() { return REQUEST_CONTEXT.get(); } public static void clear() { REQUEST_CONTEXT.remove(); } } // RestTemplate请求拦截器 public class RequestCaptureInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { RequestContextHolder.set(request.getURI().toString(), request.getMethod().name()); try { return execution.execute(request, body); } finally { // 请求结束后清理,避免内存泄漏 RequestContextHolder.clear(); } } }
- 给你使用的RestTemplate实例注册拦截器:
RestTemplate restTemplate = new RestTemplate(); restTemplate.setInterceptors(Collections.singletonList(new RequestCaptureInterceptor()));
- 调整
executeRequest的异常处理逻辑即可,不需要改任何业务调用代码:
protected ResponseEntity executeRequest(Supplier<ResponseEntity> request) { try { ResponseEntity response = request.get(); updateSessionToken(response); return response; } catch (HttpClientErrorException | HttpServerErrorException e) { Map<String, String> context = RequestContextHolder.get(); String url = context != null ? context.get("url") : "未知"; String method = context != null ? context.get("method") : "未知"; String msg = String.format("WDD3D-Error in service communication, 请求地址:%s, 请求方法:%s <br>错误响应:%s", url, method, e.getResponseBodyAsString()); throw new MaestroException(msg); } }
内容的提问来源于stack exchange,提问作者Fernando Schotten
相关产品推荐
相关产品推荐

