第一次玩微信小程序,调用第一个接口jscode2session居然就出问题了。采用RestTemplate访问https://api.weixin.qq.com/sns/jscode2session,就提示异常:

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class com.solar.app.model.weixin.WxBaseUserInfo] and content type [text/plain]

查询度娘,原因如下:

虽然这里的微信接口返回的是 Json 格式的数据,但是在返回的 Header 里面的 Content-Type 值却是 text/plain,而RestTemplate的消息转换器集合中默认是没有这个类型的,所以需要把这个类型加入到消息转换器中。

分析:

public RestTemplate() {this.messageConverters = new ArrayList();this.errorHandler = new DefaultResponseErrorHandler();this.headersExtractor = new RestTemplate.HeadersExtractor();this.messageConverters.add(new ByteArrayHttpMessageConverter());this.messageConverters.add(new StringHttpMessageConverter());this.messageConverters.add(new ResourceHttpMessageConverter(false));if (!shouldIgnoreXml) {try {this.messageConverters.add(new SourceHttpMessageConverter());} catch (Error var2) {}}this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());if (romePresent) {this.messageConverters.add(new AtomFeedHttpMessageConverter());this.messageConverters.add(new RssChannelHttpMessageConverter());}if (!shouldIgnoreXml) {if (jackson2XmlPresent) {this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());} else if (jaxb2Present) {this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());}}if (jackson2Present) {this.messageConverters.add(new MappingJackson2HttpMessageConverter());} else if (gsonPresent) {this.messageConverters.add(new GsonHttpMessageConverter());} else if (jsonbPresent) {this.messageConverters.add(new JsonbHttpMessageConverter());} else if (kotlinSerializationJsonPresent) {this.messageConverters.add(new KotlinSerializationJsonHttpMessageConverter());}if (jackson2SmilePresent) {this.messageConverters.add(new MappingJackson2SmileHttpMessageConverter());}if (jackson2CborPresent) {this.messageConverters.add(new MappingJackson2CborHttpMessageConverter());}this.uriTemplateHandler = initUriTemplateHandler();
}

而springboot内置的就是jackson来进行json的序列化和反序列号,通过debug也可以验证这一点(jackson2Present == true),也就是说RestTemplate会默认加入MappingJackson2HttpMessageConverter这个转换器,它有两个构造方法,我们可以发现其支持的MediaType为application/json

public MappingJackson2HttpMessageConverter() {this(Jackson2ObjectMapperBuilder.json().build()); // 这里调用的是第二个构造方法
}public MappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {super(objectMapper, new MediaType[]{MediaType.APPLICATION_JSON, new MediaType("application", "*+json")});
}

通过debug,发现RestTemplate会执行doExecute方法

protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {Assert.notNull(url, "URI is required");Assert.notNull(method, "HttpMethod is required");ClientHttpResponse response = null;Object var14;try {ClientHttpRequest request = this.createRequest(url, method);if (requestCallback != null) {requestCallback.doWithRequest(request);}response = request.execute();this.handleResponse(url, method, response);var14 = responseExtractor != null ? responseExtractor.extractData(response) : null;} catch (IOException var12) {String resource = url.toString();String query = url.getRawQuery();resource = query != null ? resource.substring(0, resource.indexOf(63)) : resource;throw new ResourceAccessException("I/O error on " + method.name() + " request for \"" + resource + "\": " + var12.getMessage(), var12);} finally {if (response != null) {response.close();}}return var14;
}

responseExtractor.extractData这个方法负责从httpresponse中获取数据,利用到了消息转换器。实际进入到类HttpMessageConverterExtractor中:

public T extractData(ClientHttpResponse response) throws IOException {MessageBodyClientHttpResponseWrapper responseWrapper = new MessageBodyClientHttpResponseWrapper(response);if (responseWrapper.hasMessageBody() && !responseWrapper.hasEmptyMessageBody()) {MediaType contentType = this.getContentType(responseWrapper);try {Iterator var4 = this.messageConverters.iterator();while(var4.hasNext()) {HttpMessageConverter<?> messageConverter = (HttpMessageConverter)var4.next();if (messageConverter instanceof GenericHttpMessageConverter) {GenericHttpMessageConverter<?> genericMessageConverter = (GenericHttpMessageConverter)messageConverter;
//此处即是判断消息转换器的类型是否会http响应的类型相同if (genericMessageConverter.canRead(this.responseType, (Class)null, contentType)) {if (this.logger.isDebugEnabled()) {ResolvableType resolvableType = ResolvableType.forType(this.responseType);this.logger.debug("Reading to [" + resolvableType + "]");}return genericMessageConverter.read(this.responseType, (Class)null, responseWrapper);}}if (this.responseClass != null && messageConverter.canRead(this.responseClass, contentType)) {if (this.logger.isDebugEnabled()) {String className = this.responseClass.getName();this.logger.debug("Reading to [" + className + "] as \"" + contentType + "\"");}return messageConverter.read(this.responseClass, responseWrapper);}}} catch (HttpMessageNotReadableException | IOException var8) {throw new RestClientException("Error while extracting response for type [" + this.responseType + "] and content type [" + contentType + "]", var8);}throw new UnknownContentTypeException(this.responseType, contentType, responseWrapper.getRawStatusCode(), responseWrapper.getStatusText(), responseWrapper.getHeaders(), getResponseBody(responseWrapper));} else {return null;}
}

通过红色标记的异常,正是我们程序输出的异常。不难发现,这个方法一开始就会获取所有的消息转换器,然后逐条遍历,判断是否有相应的转换器的类型与http响应类型responseType相同,如果都没有相同的,则会抛出该异常。到这里我们就会容易想到,既然原因是没有这个类型text/plain引起的,我们可以在转换器集合中添加这个类型。

两种解决方法:

1、我们可以仿造MappingJackson2HttpMessageConverter类,创建一个MyMappingJackson2HttpMessageConverter类,将里面的

super(objectMapper, new MediaType[]{MediaType.APPLICATION_JSON, new MediaType("application", "*+json")});

改为

super(objectMapper, new MediaType[]{MediaType.TEXT_PLAIN, new MediaType("text", "*+plain")});

2.也可以直接继承MappingJackson2HttpMessageConverter类,自定义MyMappingJackson2HttpMessageConverter类,在其构造方法中添加Text_PLAIN类型

public class MyMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {public WxMappingJackson2HttpMessageConverter(){List<MediaType> mediaTypes = new ArrayList<>();mediaTypes.add(MediaType.TEXT_PLAIN);setSupportedMediaTypes(mediaTypes);}
}

最后在我们的springboot项目中构建RestTemplate对象的地方,添加我们自定义的消息转换器

@Configuration
public class RestTemplateConfig {@Beanpublic RestTemplate restTemplate(RestTemplateBuilder builder){RestTemplate restTemplate = builder.build();restTemplate.getMessageConverters().add(new WxMappingJackson2HttpMessageConverter());return restTemplate;}
}

到此,分析完毕。

借鉴了下面博主的这个分析,自己也重新做了分析验证和其它的解决方法,不过殊途同归,有不正确的地方还请大佬不吝指教。RestTemplate请求Could not extract response: no suitable HttpMessageConverter found for response type.._z69183787的专栏-CSDN博客

RestTemplate调用微信小程接口异常:RestClientException: Could not extract response: no suitable HttpMessageConve相关推荐

  1. 使用RestTemplate:报错Could not extract response: no suitable HttpMessageConverter found for response typ

    项目中需要调用微信接口获取access_token等一系列和微信接口相关的操作,我使用了Spring自带的RestTemplate类来发送Get或Post请求,直接在Spring配置文件中依赖注入 & ...

  2. RestTemplate请求Could not extract response: no suitable HttpMessageConverter found for response type..

    使用 Spring Boot 写项目,需要用到微信接口获取用户信息. 在 Jessey 和 Spring RestTemplate 两个 Rest 客户端中,想到尽量不引入更多的东西,然后就选择了 S ...

  3. 【spring boot】使用RestTemplate调用微信code2Session接口

    前言 spring boot 2.1.1.RELEASE 使用RestTemplate调用微信code2Session接口 spring boot中使用RestTemplate,参考这里. 调用方法 ...

  4. 微信小程序快递java_java调用微信小程序统一下单接口

    java调用微信小程序统一下单接口 今天项目中对接微信支付这一块,记录一下 这是对接微信支付的开发文档地址 微信支付流程 流程分析: 我们可以看到,前端人员只用给我们一个code,我们通过code去获 ...

  5. uni-app开发微信小程使用腾讯位置服务获取用户的位置信息

    uni-app开发微信小程使用腾讯位置服务获取用户的位置信息 一.开通腾讯位置服务 二.编码实现 (一)获取定位坐标 (二).在项目中使用 一.开通腾讯位置服务 在这里我们先要登录腾讯我i之服务的官网 ...

  6. 微信小程热映电影导演等数据获取

    微信小程热映电影导演等数据获取 微信小程电影数据读取与呈现 我们获取了豆瓣API的电影图片,现在我们重接口在获取导演,主角,电影名等数据. 获取导演,主角,电影名等数据我们要进行封装,就要定义一个数组 ...

  7. 微信小程序接口实现加密

    微信小程序接口实现加密教程: 场景 小程序请求的所有接口参数必须加密,后台返回数据也需要加密,并且增加Token验证 一.小程序端功能编写 1.下载一份Js版的aesUtil.js源码.[注:文章末尾 ...

  8. python写的小程序怎么封装_Promise实现微信小程序接口封装过程

    Promise实现微信小程序接口封装过程 发布时间:2020-06-15 13:40:43 来源:亿速云 阅读:419 作者:鸽子 相信很多开发者都遇到过回调地狱的问题.由于微信小程序的API基本都是 ...

  9. 微信小程序支付异常:requestPayment:fail no permission

    微信小程序支付异常:requestPayment:fail no permission 参考文章: (1)微信小程序支付异常:requestPayment:fail no permission (2) ...

最新文章

  1. 计算机转进制怎么看平方,计算机数制转换
  2. 李进良/丁守谦:希望TD-LTE成为4G的统一标准
  3. 这是我的第一个python程序怎么打-我的第一个Python程序(运行)
  4. python费用结算系统_python 全栈开发,Day104(DRF用户认证,结算中心,django-redis)
  5. Intel Realsense D435 pyrealsense2 get_option_range() 获取rs.option中参数值取值范围 获取默认值
  6. python android自动化测试框架_appium+python搭建自动化测试框架_Tools安装(一)
  7. 数据库问题6-將系統資料表對應至系統檢視
  8. Echar的学习记录
  9. 文件相似度比对工具的设计与实现
  10. HDU 2825 AC自动机+状压dp
  11. 揭秘 | Akuna工作体验大揭秘
  12. 已解决:Torch not compiled with CUDA enabled
  13. Spring Cloud Gateway 服务网关的部署与使用详细介绍
  14. 数据分析常用的Excel函数合集
  15. go语言sql转struct在线工具
  16. java项目生成多个条码_java – 生成随机条形码 – 一个设计问题
  17. [枚举]Stormwind 2022杭电多校第8场 1011
  18. 解放前端工程师——手把手教你开发自己的自定义列表和自定义表单系列之一缘起
  19. C语言速成笔记 —— 考点详解 知识点图解
  20. html5怎么让图片垂直居中显示,css中如何实现图片垂直居中显示?

热门文章

  1. 中科大计算机科学与浙大比,高校实力大比拼:浙大和中科大的实力对比
  2. 如何用GraphPad Prism做统计?
  3. 客户端Mock服务端的JSON数据
  4. 大学生应该做的18件事
  5. 2021年安全员-C证(山东省-2021版)最新解析及安全员-C证(山东省-2021版)考试APP
  6. 拓展实践:系统函数的调用
  7. 华为路由器console口加密 telnet远程登录 DHCP server在路由器中的两种写法
  8. C语言二分查找(指针)
  9. 数据库常用的sql语句汇总
  10. word中自动生成递增数字