feiniaojin / graceful-response

Spring Boot接口响应处理解决方案,提供统一返回值封装、全局异常处理、自定义异常错误码、参数校验增强、断言增强等功能
https://doc.feiniaojin.com
MIT License
1.12k stars 171 forks source link

ResponseBodyAdvice 处理返回值是字符串 #2

Closed toheng closed 1 year ago

toheng commented 1 year ago

如果直接返回String类型,不会封装成统一格式,依旧是会返回字符串类型。 返回不是

{
  "code": 0,
  "msg": "ok",
  "data": "abc"
}

而是

"abc"
feiniaojin commented 1 year ago

系统提示:您的邮件被腾讯邮箱判定为垃圾邮件,请编辑后重新发送!

toheng commented 1 year ago

对于String类型的返回值, Spring会默认加载StringHttpMessageConverter解析器。当我们使用Reponse包装之后, 返回的就是Reponse.class, 需要使用MappingJackson2HttpMessageConverter解析器以及application/json媒体格式。 Spring一开始指定的是StringHttpMessageConverter解析器, 无法正常解析。 解决:用ObjectMapper转换成json字符串。

feiniaojin commented 1 year ago

非常感谢您提的宝贵意见,能发现这个地方的细节,说明您是在这个项目上花费不少时间和精力的。 关于这块返回字符串,当时的考虑是直接返回string封装的情况并不多见,大多数都是直接返回一个很多属性的对象,所以GR没有对这些场景进行适配,可以通过以下方式进行兼容:

173951428 commented 11 months ago

ok,正好看到这个开源项目,也发现了这个问题,如果返回的是单纯的字符串,却是没有进行响应的包装,对于作者 @feiniaojin 给出的解决方案,我看了下源码,其实个人觉得有更好的解决办法,只要增加一个判断即可,给出一点小小的建议,如果觉得有用可以采纳 在定义的全局响应结果类,见下面这段代码

 @Override
    public Object beforeBodyWrite(Object body,
                                  MethodParameter methodParameter,
                                  MediaType mediaType,
                                  Class<? extends HttpMessageConverter<?>> clazz,
                                  ServerHttpRequest serverHttpRequest,
                                  ServerHttpResponse serverHttpResponse) {
        if (body == null) {
            return responseFactory.newSuccessInstance();
        } else if (body instanceof Response) {
            return body;
        } else {
            return responseFactory.newSuccessInstance(body);
        }
    }

参数里面增加一个 MethodParameter returnType 判断返回值是否是String类型,如果是的话,即可对响应结果做特殊处理,然后用ObjectMapper 转json进行返回。

feiniaojin commented 11 months ago

ok,正好看到这个开源项目,也发现了这个问题,如果返回的是单纯的字符串,却是没有进行响应的包装,对于作者 @feiniaojin 给出的解决方案,我看了下源码,其实个人觉得有更好的解决办法,只要增加一个判断即可,给出一点小小的建议,如果觉得有用可以采纳 在定义的全局响应结果类,见下面这段代码

 @Override
    public Object beforeBodyWrite(Object body,
                                  MethodParameter methodParameter,
                                  MediaType mediaType,
                                  Class<? extends HttpMessageConverter<?>> clazz,
                                  ServerHttpRequest serverHttpRequest,
                                  ServerHttpResponse serverHttpResponse) {
        if (body == null) {
            return responseFactory.newSuccessInstance();
        } else if (body instanceof Response) {
            return body;
        } else {
            return responseFactory.newSuccessInstance(body);
        }
    }

参数里面增加一个 MethodParameter returnType 判断返回值是否是String类型,如果是的话,即可对响应结果做特殊处理,然后用ObjectMapper 转json进行返回。


事实上,我不建议直接返回String,这个并不是技术上实现不了,而是业务逻辑上每个团队都有自己的处理方案。

有的团队会直接返回

{
  "code": "1",
  "msg": "ok",
  "data": "abcdefg"
}

如果字符串是json字符串,例如{"key":"value"}

有的团队会说,我给啥你就返回什么,所以你必须返回以下的结果:

{
  "code": "1",
  "msg": "ok",
  "data": "{\"key\":\"value\"}"
}

如果字符串是json字符串,例如{"key":"value"}

有的团队会说,这是个json,所以你必须先反序列化,然后填充到响应中,返回以下的结果:

{
  "code": "1",
  "msg": "ok",
  "data": {
    "key": "value"
  }
}

正是由于String场景的结果,存在诸多不确定性,所以我们不对String进行处理,留给Graceful Response的用户自己实现。

大家如果用过HTTP 的Header,想必从来没有直接将Header设置为:

Response Headers: application/json

而是会:

Response Headers:
    Content-Type: application/json;charset=UTF-8