[alibaba/fastjson]FastJsonHttpMessageConverter对返回字符串多加一个双引号的问题

2025-11-12 957 views
4

加双引号这个事,严格讲,不算是问题,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

回答

3

由于一般情况下String 都是作为key 或者value来使用的,所以值是需要引号的 “here is content” , 总的来说这个不是一个需要解决的问题, 因为直接返回String也不一个的JSON格式, 建议使用response直接 write,绕过这个问题。

如果想知道具体的实现可以看一下 com.alibaba.fastjson.serializer.StringCodec

9

@neil4dong 对上面描述中“key或者value是string是加双引号的设计”也赞同。

但这个场景与上面的描述不一致。 因为虽然返回的content-type是application/json,但很明显,一个单独的字符串并不是json,上面对必须加双引号的理由,也不适用此场景。

并且业界的jackson也没有这样做

4

和 #1520 重复的问题.

json 规范. http://www.json.org/json-zh.html

单字符串是由双引号包围的任意数量Unicode字符的集合

其实jackson也是一样的,

如果不使用上面的配置,测试api的返回值是11148622114871172443

解释下这个原因: 如果使用默认的spring集成jackson, 在Controller返回String类型的时候,并不会进行json转换,非String的类型会经过jackson处理,因为一个优先级的原因,spring根据返回值类型选择转换器的时候,会优先走String的转换处理StringHttpMessageConverter,所以就是你看到的没有加双引号的,但是这并不是json的返回, 他是个纯字符串的返回.

5

@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);
    }
4

@wuwen5 类似的方案也想到了,譬如使用configureMessageConverters。但项目目前就只有这一个MessageConverter,如果使用extendMessageConverters会加载约7个MessageConverter,这会影响已上线接口的返回值。

看来只能使用上面这个替换方案了。但感觉像贴了补丁,不爽

3

这个还是有必要做一下处理。 不然用户没有办法使用String来返回json字符串了。 我打算在下个版本调整这个问题

1

FastJsonHttpMessageConverter本身是没问题的,现在这种场景需要的是String而并不是json。 我觉得这不是Fastjson的问题。

不然用户没有办法使用String来返回json字符串了。

@neil4dong ,用户要的其实并不是json字符串了,json字符串的规范本来就是带双引号的。如果说带双引号的字符串不能正确处理,说明这种场景需要的是text字符串而不是json。单字符串不加双引号它就不是json,而是普通text。

当然可以作为新的特殊特性加入,比如排除String的转换,不过不能作为默认的行为实现,因为当前的结果就是正确的。

9

@wuwen5 出现这个问题,我的第一个反应,也是在找是不是config中少了一个Feature

7

@wuwen5 你可以这样理解,不是fastjson(core)的问题,是fastjsonConverter的问题,从庐山以外来看:这就是个问题,你的converter要和spring的默认的jackson converter存在的时候对不该由jsonconverter处理的东西处理逻辑一致,处理逻辑不一致那就是wrong,最常见的用例上边已经有人说了,好多人都在直接用string来return 字符串数据,现在这样你让我变成response.write()真的很不好,我之所以出现这个问题也是因为我有些对外crontroller不能使用非标准的json格式来输出,又我找不到可以多个jsonconverter共存的方法,只能把这些json来特殊处理,返回string字符串 另外:这当然是要作为默认的实现,理由上边已经说了。

0

其实方法返回值为String的时候, 没有引号才是大家一致所期望的。 但是可能有些人已经对之前有引号的字符串做过处理。所以修改可能会导致不兼容。

0

除了优先处理 String Converter,现在有更好的解决办法吗?

7

@EnableWebMvc-->@import(DelegatingWebMvcConfiguration.class)--->WebMvcConfigurationSupport


    protected final List<HttpMessageConverter<?>> getMessageConverters() {
        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版本
0

加双引号这个事,严格讲,不算是问题,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全局处理了感觉不够规范,有注解能特殊处理下这个就好了。

7

@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);