如何避免@ResponseBody默认输出导致的常见误解?

2026-05-26 07:541阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计874个文字,预计阅读时间需要4分钟。

如何避免@ResponseBody默认输出导致的常见误解?

背景:@ResponseBody + 默认情况返回的数据格式是什么?

所谓默认情况,指的是在Spring Boot框架中,使用@ResponseBody注解的方法返回的数据格式。

内容:在Spring Boot中,当使用@ResponseBody注解的方法返回数据时,默认情况下返回的数据格式通常是JSON。

例如:

java@Controllerpublic class DemoController {

@ResponseBody @GetMapping(/demo) public DemoVO demo() { return new DemoVO(); }}

在这个例子中,当调用`/demo`接口时,返回的数据格式默认是JSON。如果需要返回其他格式的数据,可以通过配置produces属性来实现。例如:

java@Controllerpublic class DemoController {

@ResponseBody @GetMapping(value=/demo, produces=MediaType.APPLICATION_XML_VALUE) public DemoVO demo() { return new DemoVO(); }}

在这个例子中,通过设置produces属性为`MediaType.APPLICATION_XML_VALUE`,返回的数据格式将变为XML。

背景

@ResponseBody 默认情况返回的数据格式是什么?所谓默认情况 后台接口不指定 produces MediaType

@Controller public class DemoController { @ResponseBody @GetMapping(value = "/demo") public DemoVO demo() { return new DemoVO("lengleng", "123456"); } }

使用百度搜索 @ResponseBody 排名第一的答案, @ResponseBody 的作用其实是将 java 对象转为 json 格式的数据。

正确答案

我们先来公布正确的答案。

@ResponseBody 的输出格式,默认情况取决于客户端的 Accept 请求头。

如何避免@ResponseBody默认输出导致的常见误解?

源码剖析

RequestResponseBodyMethodProcessor

public class RequestResponseBodyMethodProcessor { // 处理 ResponseBody 标注的方法 @Override public boolean supportsReturnType(MethodParameter returnType) { return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class)); } // 处理返回值 @Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) { mavContainer.setRequestHandled(true); ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); // 处理返回值 writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage); } }

writeWithMessageConverters

protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) { HttpServletRequest request = inputMessage.getServletRequest(); // 获取请求头中的目标资源类型 List<MediaType> acceptableTypes = getAcceptableMediaTypes(request); // 获取接口指定支持的资源类型 List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType); // 获取能够输出资源类型 List<MediaType> mediaTypesToUse = new ArrayList<>(); for (MediaType requestedType : acceptableTypes) { for (MediaType producibleType : producibleTypes) { if (requestedType.isCompatibleWith(producibleType)) { mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType)); } } } /// 排序 MediaType.sortBySpecificityAndQuality(mediaTypesToUse); for (MediaType mediaType : mediaTypesToUse) { // 判断资源类型是否是具体的类型,而不是带通配符 * 这种 if (mediaType.isConcrete()) { selectedMediaType = mediaType; break; } else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) { selectedMediaType = MediaType.APPLICATION_OCTET_STREAM; break; } } selectedMediaType = selectedMediaType.removeQualityValue(); // 查找支持选中资源类型的 HttpMessageConverter,输出body for (HttpMessageConverter<?> converter : this.messageConverters) { GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null); if (genericConverter != null ? ((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) : converter.canWrite(valueType, selectedMediaType)) { body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType, (Class<? extends HttpMessageConverter<?>>) converter.getClass(), inputMessage, outputMessage); return; } } }

为什么我要去研究这个问题

当升级至 spring cloud alibaba 2.2.1 时, sentinel 模块 引入以下依赖

当依赖中出现 dataformat jar 时候, RestTemplate ,会在默认 Accept 请求头增加

application/xml | text/xml | application/*+xml

public MappingJackson2XmlHttpMessageConverter(ObjectMapper objectMapper) { super(objectMapper, new MediaType("application", "xml", StandardCharsets.UTF_8), new MediaType("text", "xml", StandardCharsets.UTF_8), new MediaType("application", "*+xml", StandardCharsets.UTF_8)); Assert.isInstanceOf(XmlMapper.class, objectMapper, "XmlMapper required"); }

当我们使用 RestTemplate 调用接口时候,若不指定 Accept 会返回 XML ,导致不能平滑升级

到此这篇关于关于@ResponseBody 默认输出的误区的解答的文章就介绍到这了,更多相关@ResponseBody 默认输出内容请搜索易盾网络以前的文章或继续浏览下面的相关文章希望大家以后多多支持易盾网络!

标签:误区解答

本文共计874个文字,预计阅读时间需要4分钟。

如何避免@ResponseBody默认输出导致的常见误解?

背景:@ResponseBody + 默认情况返回的数据格式是什么?

所谓默认情况,指的是在Spring Boot框架中,使用@ResponseBody注解的方法返回的数据格式。

内容:在Spring Boot中,当使用@ResponseBody注解的方法返回数据时,默认情况下返回的数据格式通常是JSON。

例如:

java@Controllerpublic class DemoController {

@ResponseBody @GetMapping(/demo) public DemoVO demo() { return new DemoVO(); }}

在这个例子中,当调用`/demo`接口时,返回的数据格式默认是JSON。如果需要返回其他格式的数据,可以通过配置produces属性来实现。例如:

java@Controllerpublic class DemoController {

@ResponseBody @GetMapping(value=/demo, produces=MediaType.APPLICATION_XML_VALUE) public DemoVO demo() { return new DemoVO(); }}

在这个例子中,通过设置produces属性为`MediaType.APPLICATION_XML_VALUE`,返回的数据格式将变为XML。

背景

@ResponseBody 默认情况返回的数据格式是什么?所谓默认情况 后台接口不指定 produces MediaType

@Controller public class DemoController { @ResponseBody @GetMapping(value = "/demo") public DemoVO demo() { return new DemoVO("lengleng", "123456"); } }

使用百度搜索 @ResponseBody 排名第一的答案, @ResponseBody 的作用其实是将 java 对象转为 json 格式的数据。

正确答案

我们先来公布正确的答案。

@ResponseBody 的输出格式,默认情况取决于客户端的 Accept 请求头。

如何避免@ResponseBody默认输出导致的常见误解?

源码剖析

RequestResponseBodyMethodProcessor

public class RequestResponseBodyMethodProcessor { // 处理 ResponseBody 标注的方法 @Override public boolean supportsReturnType(MethodParameter returnType) { return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class)); } // 处理返回值 @Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) { mavContainer.setRequestHandled(true); ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); // 处理返回值 writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage); } }

writeWithMessageConverters

protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) { HttpServletRequest request = inputMessage.getServletRequest(); // 获取请求头中的目标资源类型 List<MediaType> acceptableTypes = getAcceptableMediaTypes(request); // 获取接口指定支持的资源类型 List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType); // 获取能够输出资源类型 List<MediaType> mediaTypesToUse = new ArrayList<>(); for (MediaType requestedType : acceptableTypes) { for (MediaType producibleType : producibleTypes) { if (requestedType.isCompatibleWith(producibleType)) { mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType)); } } } /// 排序 MediaType.sortBySpecificityAndQuality(mediaTypesToUse); for (MediaType mediaType : mediaTypesToUse) { // 判断资源类型是否是具体的类型,而不是带通配符 * 这种 if (mediaType.isConcrete()) { selectedMediaType = mediaType; break; } else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) { selectedMediaType = MediaType.APPLICATION_OCTET_STREAM; break; } } selectedMediaType = selectedMediaType.removeQualityValue(); // 查找支持选中资源类型的 HttpMessageConverter,输出body for (HttpMessageConverter<?> converter : this.messageConverters) { GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null); if (genericConverter != null ? ((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) : converter.canWrite(valueType, selectedMediaType)) { body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType, (Class<? extends HttpMessageConverter<?>>) converter.getClass(), inputMessage, outputMessage); return; } } }

为什么我要去研究这个问题

当升级至 spring cloud alibaba 2.2.1 时, sentinel 模块 引入以下依赖

当依赖中出现 dataformat jar 时候, RestTemplate ,会在默认 Accept 请求头增加

application/xml | text/xml | application/*+xml

public MappingJackson2XmlHttpMessageConverter(ObjectMapper objectMapper) { super(objectMapper, new MediaType("application", "xml", StandardCharsets.UTF_8), new MediaType("text", "xml", StandardCharsets.UTF_8), new MediaType("application", "*+xml", StandardCharsets.UTF_8)); Assert.isInstanceOf(XmlMapper.class, objectMapper, "XmlMapper required"); }

当我们使用 RestTemplate 调用接口时候,若不指定 Accept 会返回 XML ,导致不能平滑升级

到此这篇关于关于@ResponseBody 默认输出的误区的解答的文章就介绍到这了,更多相关@ResponseBody 默认输出内容请搜索易盾网络以前的文章或继续浏览下面的相关文章希望大家以后多多支持易盾网络!

标签:误区解答