加双引号这个事,严格讲,不算是问题,app等前端都会处理。但是做公众号开发时,如果返回的字符串加了双引号,微信服务器就检验不过。导致无法配置服务器(这一步的操作会不成功https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1472017492_58YV5)
现象描述:
锁定问题用的test api:
@RestController
public class CustomController {
@RequestMapping("/test")
public String init() {
return "11148622114871172443";
}
}
如果使用下面的配置,则测试api的返回值是 "11148622114871172443" 【微信服务器会校验不过】
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
FastJsonHttpMessageConverter httpMessageConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.QuoteFieldNames,
SerializerFeature.WriteEnumUsingToString,
SerializerFeature.WriteMapNullValue,
SerializerFeature.WriteDateUseDateFormat,
SerializerFeature.DisableCircularReferenceDetect);
fastJsonConfig.setSerializeFilters((ValueFilter) (o, s, source) -> {
if (source == null) {
return "";
}
if (source instanceof Date) {
return ((Date) source).getTime();
}
return source;
});
httpMessageConverter.setFastJsonConfig(fastJsonConfig);
converters.add(httpMessageConverter);
}
如果不使用上面的配置,测试api的返回值是11148622114871172443,微信服务器核验通过
锁定问题的测试的代码已上传:https://github.com/helloworldtang/mp-demo
由于一般情况下String 都是作为key 或者value来使用的,所以值是需要引号的 “here is content” ,
总的来说这个不是一个需要解决的问题, 因为直接返回String也不一个的JSON格式, 建议使用response直接 write,绕过这个问题。
如果想知道具体的实现可以看一下 com.alibaba.fastjson.serializer.StringCodec
@neil4dong
对上面描述中“key或者value是string是加双引号的设计”也赞同。
但这个场景与上面的描述不一致。
因为虽然返回的content-type是application/json,但很明显,一个单独的字符串并不是json,上面对必须加双引号的理由,也不适用此场景。
并且业界的jackson也没有这样做
和 #1520 重复的问题.
json 规范.
http://www.json.org/json-zh.html
单字符串是由双引号包围的任意数量Unicode字符的集合
其实jackson也是一样的,
如果不使用上面的配置,测试api的返回值是11148622114871172443
解释下这个原因: 如果使用默认的spring集成jackson, 在Controller返回String类型的时候,并不会进行json转换,非String的类型会经过jackson处理,因为一个优先级的原因,spring根据返回值类型选择转换器的时候,会优先走String的转换处理StringHttpMessageConverter,所以就是你看到的没有加双引号的,但是这并不是json的返回, 他是个纯字符串的返回.
@helloworldtang 参考spring默认的转换器顺序,你的代码可以这样改下测试。
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
FastJsonHttpMessageConverter httpMessageConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.QuoteFieldNames,
SerializerFeature.WriteEnumUsingToString,
SerializerFeature.WriteMapNullValue,
SerializerFeature.WriteDateUseDateFormat,
SerializerFeature.DisableCircularReferenceDetect);
fastJsonConfig.setSerializeFilters((ValueFilter) (o, s, source) -> {
if (source == null) {
return "";
}
if (source instanceof Date) {
return ((Date) source).getTime();
}
return source;
});
httpMessageConverter.setFastJsonConfig(fastJsonConfig);
StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
stringConverter.setWriteAcceptCharset(false);
//增加两个优先处理的转换类型.
converters.add(new ByteArrayHttpMessageConverter());
converters.add(stringConverter);
converters.add(httpMessageConverter);
}
@wuwen5
类似的方案也想到了,譬如使用configureMessageConverters。但项目目前就只有这一个MessageConverter,如果使用extendMessageConverters会加载约7个MessageConverter,这会影响已上线接口的返回值。
看来只能使用上面这个替换方案了。但感觉像贴了补丁,不爽
这个还是有必要做一下处理。 不然用户没有办法使用String来返回json字符串了。
我打算在下个版本调整这个问题
FastJsonHttpMessageConverter本身是没问题的,现在这种场景需要的是String而并不是json。 我觉得这不是Fastjson的问题。
不然用户没有办法使用String来返回json字符串了。
@neil4dong ,用户要的其实并不是json字符串了,json字符串的规范本来就是带双引号的。如果说带双引号的字符串不能正确处理,说明这种场景需要的是text字符串而不是json。单字符串不加双引号它就不是json,而是普通text。
当然可以作为新的特殊特性加入,比如排除String的转换,不过不能作为默认的行为实现,因为当前的结果就是正确的。
@wuwen5 出现这个问题,我的第一个反应,也是在找是不是config中少了一个Feature
@wuwen5 你可以这样理解,不是fastjson(core)的问题,是fastjsonConverter的问题,从庐山以外来看:这就是个问题,你的converter要和spring的默认的jackson converter存在的时候对不该由jsonconverter处理的东西处理逻辑一致,处理逻辑不一致那就是wrong,最常见的用例上边已经有人说了,好多人都在直接用string来return 字符串数据,现在这样你让我变成response.write()真的很不好,我之所以出现这个问题也是因为我有些对外crontroller不能使用非标准的json格式来输出,又我找不到可以多个jsonconverter共存的方法,只能把这些json来特殊处理,返回string字符串
另外:这当然是要作为默认的实现,理由上边已经说了。
其实方法返回值为String的时候, 没有引号才是大家一致所期望的。
但是可能有些人已经对之前有引号的字符串做过处理。所以修改可能会导致不兼容。
除了优先处理 String Converter,现在有更好的解决办法吗?
@EnableWebMvc-->@import(DelegatingWebMvcConfiguration.class)--->WebMvcConfigurationSupport
```java
protected final List
if (this.messageConverters == null) {
this.messageConverters = new ArrayList<>();
configureMessageConverters(this.messageConverters);
if (this.messageConverters.isEmpty()) {
addDefaultHttpMessageConverters(this.messageConverters);
}
extendMessageConverters(this.messageConverters);
}
return this.messageConverters;
}
在WebMvcConfigurationSupport的getMessageConverters中先通过configureMessageConverters方法添
加自定义MessageConverter,如若自定义了就不会注入默认的Converter,因此可以通过
extendMessageConverters 这个方法来扩展MessageConverter,这个方法是在注入默认的converter之后
执行的。
另外 addDefaultHttpMessageConverters 方法在检测到gson依赖时会自动创建
GsonHttpMessageConverter,具体可见源码。
注:以上分析基于 spring 5.0.4.RELEASE版本
加双引号这个事,严格讲,不算是问题,app等前端都会处理。但是做公共号开发时,如果返回的字符串加了双引号,微信服务器就检验不过。导致无法配置服务器操作会不成功https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1472017492_58YV5)
现象描述:
锁定问题用的test api:
@RestController 公共 类 CustomController { @RequestMapping(“ / test ”) public String init(){ return “ 11148622114871172443 ” ; } }如果使用下面的配置,则测试api的返回值是“ 11148622114871172443”【微信服务器会校验不过】
@Override public void configureMessageConverters(List < HttpMessageConverter <? >>转换器){ FastJsonHttpMessageConverter httpMessageConverter = new FastJsonHttpMessageConverter(); FastJsonConfig fastJsonConfig = 新的 FastJsonConfig(); fastJsonConfig 。setSerializerFeatures(SerializerFeature 。QuoteFieldNames, SerializerFeature 。WriteEnumUsingToString, SerializerFeature 。WriteMapNullValue, SerializerFeature 。WriteDateUseDateFormat, SerializerFeature 。DisableCircularReferenceDetect); fastJsonConfig 。setSerializeFilters((ValueFilter)(o,s,source)- > { if(source == null){ return “ ” ; } if(source instanceof Date){ 返回((Date)source)。getTime(); } 返回源 }); httpMessageConverter 。setFastJsonConfig(fastJsonConfig); 转换器。添加(httpMessageConverter); }如果不使用上面的配置,测试api的返回值是11148622114871172443,微信服务器核验通过
锁定问题的测试的代码已上传:https : //github.com/helloworldtang/mp-demo
response.getWriter().write(request.getParameter("echostr"));
用原生的写法处理了,消息转换器加StringHttpMessageConverter全局处理了感觉不够规范,有注解能特殊处理下这个就好了。
@helloworldtang 参考spring默认的转换器顺序,你的代码可以这样改下测试。
@Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { FastJsonHttpMessageConverter httpMessageConverter = new FastJsonHttpMessageConverter(); FastJsonConfig fastJsonConfig = new FastJsonConfig(); fastJsonConfig.setSerializerFeatures(SerializerFeature.QuoteFieldNames, SerializerFeature.WriteEnumUsingToString, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat, SerializerFeature.DisableCircularReferenceDetect); fastJsonConfig.setSerializeFilters((ValueFilter) (o, s, source) -> { if (source == null) { return ""; } if (source instanceof Date) { return ((Date) source).getTime(); } return source; }); httpMessageConverter.setFastJsonConfig(fastJsonConfig); StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(); stringConverter.setWriteAcceptCharset(false); //增加两个优先处理的转换类型. converters.add(new ByteArrayHttpMessageConverter()); converters.add(stringConverter); converters.add(httpMessageConverter); }
converters.add(3, httpMessageConverter);
Most helpful comment
@helloworldtang 参考spring默认的转换器顺序,你的代码可以这样改下测试。