You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot微服务调用出现No converter found错误排查求助

Spring Boot微服务返回HashMap时触发HttpMessageNotWritableException问题

问题背景

开发了两个Spring Boot微服务:Service-one和Service-two,其中Service-one通过WebClient调用Service-two的接口获取数据。调用Service-one的/products接口时,抛出No converter found for return value of type: class java.util.HashMap错误。已使用@RestController(无需额外@ResponseBody),且已添加Jackson依赖,问题仍未解决。

相关代码

Service-one Controller

@Autowired
WebClient client;

HashMap<String,Object> finalList =  new HashMap<String, Object>();
HashMap<Integer, String> productMap = new HashMap<Integer, String>();

@PostMapping(value = "/products/{id}")
public void saveData(@PathVariable("id") Integer id, @RequestBody String message) {
    productMap.put(id, message);
}

@GetMapping(value = "/products")
public HashMap<String, Object> getMessage() {
    Map<String, Object> details  = client.get().uri("/details").retrieve().bodyToFlux(new ParameterizedTypeReference<Map<String,Object>>(){})
            .blockFirst();
    finalList.put("details", details);
    
    return  finalList;
}

Service-two Controller

@RestController
@RequestMapping(value = "/details-service")
public class DetailsServiceController {
    
    @GetMapping(value = "/details")
    private HashMap<String, Object> getDetails() {
        HashMap<String, Object> additionalDetails = new HashMap<String, Object>();
        ArrayList<String> array = new ArrayList<String>();
        additionalDetails.put("version", 1);
        array.add("ABC.com");
        additionalDetails.put("vendors", array);
        return additionalDetails;
    }
}

错误日志

org.springframework.http.converter.HttpMessageNotWritableException: No converter found for return value of type: class java.util.HashMap
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:230) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:181) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:82) ~[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:123) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.33.jar:9.0.33]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.33.jar:9.0.33]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.33.jar:9.0.33]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.33.jar:9.0.33]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.33.jar:9.0.33]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.33.jar:9.0.33]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.33.jar:9.0.33]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.33.jar:9.0.33]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373) [tomcat-embed-core-9.0.33.jar:9.0.33]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.33.jar:9.0.33]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-9.0.33.jar:9.0.33]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1594) [tomcat-embed-core-9.0.33.jar:9.0.33]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.33.jar:9.0.33]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_251]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_251]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.33.jar:9.0.33]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_251]

解决方案建议

1. 修正Service-two接口方法的访问权限

Service-two中getDetails()方法是private修饰的,Spring无法识别并映射这个接口方法,导致Service-one调用时返回异常数据。将其改为public:

@GetMapping(value = "/details")
public HashMap<String, Object> getDetails() {
    // 原有逻辑不变
}

2. 修正WebClient的请求路径

Service-two的接口路径是/details-service/details,但Service-one中WebClient调用的是/details,路径不匹配导致调用失败。需配置WebClient的baseUrl,或者修改请求uri:

// 方式一:配置WebClient Bean时指定baseUrl
@Bean
public WebClient webClient() {
    return WebClient.builder()
            .baseUrl("http://localhost:端口号/details-service") // 替换为Service-two的实际地址和端口
            .build();
}

// 方式二:在调用时使用完整路径
Map<String, Object> details = client.get().uri("/details-service/details")
        .retrieve().bodyToFlux(new ParameterizedTypeReference<Map<String,Object>>(){})
        .blockFirst();

3. 避免使用类级别的全局变量存储返回数据

finalList是类成员变量,属于全局共享状态,线程不安全且可能导致序列化异常。应在方法内部创建局部变量:

@GetMapping(value = "/products")
public Map<String, Object> getMessage() {
    Map<String, Object> finalList = new HashMap<>();
    Map<String, Object> details = client.get().uri("/details").retrieve()
            .bodyToFlux(new ParameterizedTypeReference<Map<String,Object>>(){})
            .blockFirst();
    finalList.put("details", details);
    
    return finalList;
}

4. 方法返回类型改用接口而非具体实现类

将返回类型从HashMap<String, Object>改为Map<String, Object>,Spring MVC对接口类型的序列化支持更稳定:

@GetMapping(value = "/products")
public Map<String, Object> getMessage() {
    // 原有逻辑不变
}

5. 确认Jackson依赖的正确性

Spring Boot Starter Web默认包含jackson-databind依赖,若手动添加Jackson依赖,需确保版本与Spring Boot版本匹配。检查pom.xml(Maven)或build.gradle(Gradle)中的依赖配置,避免版本冲突。


内容的提问来源于stack exchange,提问作者arj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 02:30:44