StringHttpMessageConverter

2020-08-30   


StringHttpMessageConverter

场景

  最近在写一个对接第三方的接口时发现最后接口返回的参数变成了带有转义符的JSON字符串:

"{\"code\":0,\"message\":null,\"data\":\"eyJuYW1lIjoi6YW35YWSIn0=\"}"

其他接口都返回的是正常的JSON数据。

原因分析

  项目中原本已经定义了一个@ControllerAdvice用于对出参进行统一封装,而此接口由于需要对出参进行加密处理,所以会经过另一个用于出参统一加密的@ControllerAdvice。

@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
    //todo
    String body = JacksonHelper.objectToJson(o);
    return Base64Encoder.encode(body.getBytes(StandardCharsets.UTF_8));
}

到这里加密后的出参并没有什么问题,那么问题估计就是在出参统一分装的地方了,看下代码。

@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
    if (o instanceof byte[]) {
        return o;
    } else if (o instanceof ResponseResult) {
        return o;
    } else if (o instanceof String) {
        return JacksonHelper.objectToJson(new ResponseResult().setData(o));
    }else {
        return new ResponseResult().setData(o);
    }
}

奇怪的地方来了,这边对于String类型的出参额外进行了转json字符串的过程,好像是多此一举,把它干掉。
现在接口的返回没问题了。

{
    "code": 0,
    "message": null,
    "data": "eyJuYW1lIjoi6YW35YWSIn0="
}

但是等等,以前一个返回值类型为String的不需要加密的接口直接500了?

@RequestMapping("/xxxx")
public String xxxx() {
    //todo
    return "酷兒";
}

看下报错信息

java.lang.ClassCastException: com.rin.halodemo.response.ResponseResult cannot be cast to java.lang.String
	at org.springframework.http.converter.StringHttpMessageConverter.addDefaultHeaders(StringHttpMessageConverter.java:44) ~[spring-web-5.3.8.jar:5.3.8]
	at org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:211) ~[spring-web-5.3.8.jar:5.3.8]
	at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:293) ~[spring-webmvc-5.3.8.jar:5.3.8]
	at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:181) ~[spring-webmvc-5.3.8.jar:5.3.8]
	at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:78) ~[spring-web-5.3.8.jar:5.3.8]

类型转换错误,出参对象无法被转换为String。看起来像是由于我们将String类型的出参统一包装为ResponseResult参数类型而导致StringHttpMessageConverter无法对它进行转换。

解决

既然StringHttpMessageConverter处理会发生异常,那就改为其他converter好了。SpringBoot默认使用的是MappingJackson2HttpMessageConverter,将它提前就好。

@Configuration
public class WebMvcConfigure implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        //todo
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        converters.add(0, new MappingJackson2HttpMessageConverter(objectMapper));
    }

}

问题解决,接口返回正确。

{
"code": 0,
"message": null,
"data": "IumFt+WFkiI="
}
其他

没了_(:з」∠)_

Q.E.D.