26 记一次 SpringMVC 406 The resource identified by this request is only capable of generating responses

本文主要是介绍26 记一次 SpringMVC 406 The resource identified by this request is only capable of generating responses,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 

问题如下图所示

 

/common/test406.html, 此接口访问的是 SpringMVC 的一个 Controller 的一个 接口, 该接口上面有 @ResponseBody, 意图为作为一个提供数据的数据接口
 

当天晚上[10月18日晚]跟了一下代码, 差不多是临时解决了一下问题, 思路在后面

当天晚上是花了很多时间的, 突然 发现了自己对于 SpringMVC 这个框架的认识还太浅, 虽然 以前也看过脉络的代码, 但是 久而久之就忘记了, 然后 今天重新更了一下大体流程的代码

 

这里总结下, 之前的一个问题, 我注册了一个 mvcContentNegotiationManager, 然后 之后就解决了之前的一个 .html 访问 某一@ResponseBody 接口响应406的问题, 
<mvc:annotation-driven />, 这里的的 AnnotationDrivenBeanDefinitionParser, 想 ac 中注入了一个 

RootBeanDefinition factoryBeanDef = new RootBeanDefinition(ContentNegotiationManagerFactoryBean.class);
factoryBeanDef.setSource(source);
factoryBeanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
factoryBeanDef.getPropertyValues().add("mediaTypes", getDefaultMediaTypes());


创建的是一个 ContentNegotiationManagerFactoryBean, 然后 之后的时候, 触发了 afterPropertiesSet 初始化, 然后 想contentNegotiationManager[前者] 中增加了 ServletPathExtensionContentNegotiationStrategy, 然后 之后是默认的 HeaderContentNegotiationStrategy
我自己定义的 id为 mvcContentNegotiationManager[后者], 直接使用 类的初始化方法进行初始化, 里面默认有一个 HeaderContentNegotiationStrategy


然后 在这里访问接口的时候, 前者拦截了 .html 然后查询请求需要的类型, ServletPathExtensionContentNegotiationStrategy 在HeaderContentNegotiationStrategy之前, 然后拿到请求的需要的类型为 text/html, 然后响应这边给出的 Content-Type 为  application/json;charset=UTF-8, application/*+json;charset=UTF-8
然后 请求和响应的MimeType 不兼容, 然后 走了后面的  "throw new HttpMediaTypeNotAcceptableException"


然后 后者, 通过 HeaderContentNegotiationStrategy, 在 header 获取客户端接收的类型, 其中有一个; */*吧, 支持所有类型, 这个兼容响应的类型, 然后 就通过了


ContentNegotiationManager. resolveMediaTypes

public List<MediaType> resolveMediaTypes(NativeWebRequest request)throws HttpMediaTypeNotAcceptableException {for (ContentNegotiationStrategy strategy : this.strategies) {List<MediaType> mediaTypes = strategy.resolveMediaTypes(request);if (mediaTypes.isEmpty() || mediaTypes.equals(MEDIA_TYPE_ALL)) {continue;}return mediaTypes;}return Collections.emptyList();
}
if (compatibleMediaTypes.isEmpty()) {if (returnValue != null) {throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);}return;
}




然后 这里还有一个需要注意的问题, 容器的初始化流程, 
<mvc:annotation-driven />
<bean id="mvcContentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManager"/>
这样的顺序是没有问题的, 因为后来的 beanDef 覆盖了前面的 AnnotationDrivenBeanDefinitionParser 中向 ac 中注册的beanDef, 
但是 反过来, 执行的最终容器中保留的就是, ContentNegotiationManagerFactoryBean 计算得到的 contentNegotiationManager, 然后 因此, 之前的 406 会出现


此问题, 另外一种解决思路是, 去掉请求时候的后缀, 或者更换后缀, 此ServletPathExtensionContentNegotiationStrategy 默认支持的后缀来自于, 其依赖的 ContentNegotiationManager 为["xml" -> "application/xml", "json" -> "application/json"] 以及handleNoMatch的时候支持的 FileTypeMap. getDefaultFileTypeMap
默认的 ContentNegotiationManager初始化部分具体的代码请参见 : AnnotationDrivenBeanDefinitionParser. getContentNegotiationManager

 


http://www.codeweblog.com/%E8%A7%A3%E5%86%B3springmvc%E4%B8%AD%E7%9A%84-could-not-find-acceptable-represent/


此问题, 还有一个奇葩的插曲, 我按照上面的链接的方式修改了之后, 我这边没有问题了, 然后 同事那边更新了之后, 缺访问不了静态资源了, 然后 我clean了一下浏览器的缓存, 然后 刷新发现依然能够拿到静态资源
这里不能拿到静态资源也不难理解, 相关的请求被 dispatcherServlet, 拦截了, 然后 被internalResourceViewResolver拦截了, 然后 在/WEB-INF/pages 下面找资源, 然而 真正的资源在外层的 webapps/$CONTEXT_PATH/static
然后 dispatcherServlet 拦截的 url-pattern 为 *.html 的时候, 静态资源相关请求是被 Tomcat 的 DefaultServlet 来处理
然后 之后的时候, 同事更新了一下代码, 增加了 MappingJackson2HttpMessageConverter 的配置, 然后加入了一些依赖之后, 就能够通过 .html 访问道接口, 拿到正确的数据了, 


详细的细节, 以及追一下, 如下图的代码, 

 

--------------------------------------------------------------------------------


最后的时候, 说一下, 构造此种情况的方法
1. web.xml 中的配置

	<servlet><servlet-name>springDispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring/applicationContext-mvc.xml</param-value></init-param><load-on-startup>2</load-on-startup></servlet><servlet-mapping><servlet-name>springDispatcherServlet</servlet-name><url-pattern>*.html</url-pattern></servlet-mapping>


2. applicationContext-mvc.xml 中添加 <mvc:annotation-driven />
3. 增加 @Controller

 

    @RequestMapping(value = "test406")@ResponseBodypublic JSONObject test406(HttpServletRequest request, HttpServletResponse response) throws Exception {JSONObject result = new JSONObject();result.put("k", "v");return result;}

 

======================= add at 2018.11.28 ======================= 

上周四的时候, 我们同事 同样是碰到了一个这样的 406 的问题, 然后 我就感觉之前遇到过 

然后 之后今天的时候, 看了一下, 跟了一下流程 

 

示例代码如下 

直接 发送http请求, 我们期望拿到的是 一个正确的 json 结果, 但是 实际上返回的是 一个 406 的错误页面 

然后 假设 吧 "doc.list" 更新为 "doc.list1", 然后 就能够拿到 期望的正确页面, 那么这个是怎么回事呢?? 

 

我们这里的 mvcContentNegotiationManager 属于上面的前者, 使用的是 AnnotationDrivenBeanDefinitionParser 处理的过程中注入的 mvcContentNegotiationManager, 优先使用 ServletPathExtensionContentNegotiationStrategy 解析客户端请求的 mimeType, 然后再尝试 使用 HeaderContentNegotiationStrategy 来解析 客户端请求的 mimeType 

使用"doc.list", 调试发现, 使用 ServletPathExtensionContentNegotiationStrategy 首先 lookupMediaType 没有找到 "list" 对应的 mimeType, 然后 在 handleNoMatch 的补偿中 在 ServletContext -> StandardContext 中找到了 list 对应的 mimeType 为 "text/plain", 然后 就返回回去了

然后 实际响应的类型是 "application/json" 和 "application/*+json", 请求类型 和响应类型 不兼容 走了后面的  "throw new HttpMediaTypeNotAcceptableException"

 

使用"doc.list1", 调试发现, 两个 NegotiationStrategy 都没有从请求中找到合适的类型, 然后使用了 默认的 "*/*", 接受所有的类型 

 

AbstractMappingContentNegotiationStrategy. resolveMediaTypeKey

public List<MediaType> resolveMediaTypeKey(NativeWebRequest webRequest, String key)throws HttpMediaTypeNotAcceptableException {if (StringUtils.hasText(key)) {MediaType mediaType = lookupMediaType(key);if (mediaType != null) {handleMatch(key, mediaType);return Collections.singletonList(mediaType);}mediaType = handleNoMatch(webRequest, key);        // line : 78if (mediaType != null) {addMapping(key, mediaType);return Collections.singletonList(mediaType);}}return Collections.emptyList();
}

 

 

参考连接

http://www.codeweblog.com/%E8%A7%A3%E5%86%B3springmvc%E4%B8%AD%E7%9A%84-could-not-find-acceptable-represent/

 

 

这篇关于26 记一次 SpringMVC 406 The resource identified by this request is only capable of generating responses的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1010983

相关文章

Spring Cloud LoadBalancer 负载均衡详解

《SpringCloudLoadBalancer负载均衡详解》本文介绍了如何在SpringCloud中使用SpringCloudLoadBalancer实现客户端负载均衡,并详细讲解了轮询策略和... 目录1. 在 idea 上运行多个服务2. 问题引入3. 负载均衡4. Spring Cloud Load

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

在 Spring Boot 中使用 @Autowired和 @Bean注解的示例详解

《在SpringBoot中使用@Autowired和@Bean注解的示例详解》本文通过一个示例演示了如何在SpringBoot中使用@Autowired和@Bean注解进行依赖注入和Bean... 目录在 Spring Boot 中使用 @Autowired 和 @Bean 注解示例背景1. 定义 Stud

如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解

《如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解》:本文主要介绍如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别的相关资料,描述了如何使用海康威视设备网络SD... 目录前言开发流程问题和解决方案dll库加载不到的问题老旧版本sdk不兼容的问题关键实现流程总结前言作为

SpringBoot中使用 ThreadLocal 进行多线程上下文管理及注意事项小结

《SpringBoot中使用ThreadLocal进行多线程上下文管理及注意事项小结》本文详细介绍了ThreadLocal的原理、使用场景和示例代码,并在SpringBoot中使用ThreadLo... 目录前言技术积累1.什么是 ThreadLocal2. ThreadLocal 的原理2.1 线程隔离2

springboot将lib和jar分离的操作方法

《springboot将lib和jar分离的操作方法》本文介绍了如何通过优化pom.xml配置来减小SpringBoot项目的jar包大小,主要通过使用spring-boot-maven-plugin... 遇到一个问题,就是每次maven package或者maven install后target中的ja

Java中八大包装类举例详解(通俗易懂)

《Java中八大包装类举例详解(通俗易懂)》:本文主要介绍Java中的包装类,包括它们的作用、特点、用途以及如何进行装箱和拆箱,包装类还提供了许多实用方法,如转换、获取基本类型值、比较和类型检测,... 目录一、包装类(Wrapper Class)1、简要介绍2、包装类特点3、包装类用途二、装箱和拆箱1、装

如何利用Java获取当天的开始和结束时间

《如何利用Java获取当天的开始和结束时间》:本文主要介绍如何使用Java8的LocalDate和LocalDateTime类获取指定日期的开始和结束时间,展示了如何通过这些类进行日期和时间的处... 目录前言1. Java日期时间API概述2. 获取当天的开始和结束时间代码解析运行结果3. 总结前言在J

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动