以 .au 结尾的 URI 上的 Spring 更改媒体类型
Posted
技术标签:
【中文标题】以 .au 结尾的 URI 上的 Spring 更改媒体类型【英文标题】:Spring changing media type on URI with .au at the end 【发布时间】:2017-05-06 20:52:59 【问题描述】:目前实现的 REST 端点如下:
@RequestMapping(path = "/login/user/username:.+", method = POST, produces = "application/json; charset=utf-8")
@ResponseStatus(code = HttpStatus.OK)
public User userLogin(@PathVariable("username") String username, @RequestBody Password password)
//do stuff
return new User(UUID.randomUUID());
我目前使用电子邮件地址作为用户名,当我使用以 .au 结尾的用户名时,端点返回 406 内容不可接受。
我试着把上面的改成这个
@RequestMapping(path = "/login/user/username:.+", method = POST, produces = "application/json; charset=utf-8")
@ResponseStatus(code = HttpStatus.OK)
public String userLogin(@PathVariable("username") String username, @RequestBody Password password)
//do stuff
return "blah";
当我访问它时,它会提示我下载一个 .au 文件(由 Sun 微系统制作的音频格式...),其中包含“blah”。 如果我在方法中随时检查用户名的值,我会得到正确的电子邮件地址,包括 .au。
我猜测 Spring 堆栈中的某些东西正在解析 .au 并尝试强制执行不同的媒体类型,所以现在它忽略了 application/json
【问题讨论】:
【参考方案1】:我最近遇到了同样的问题并发现了问题。想在这里分享它,因为它会帮助别人。 @Patrick 解释的这种行为似乎是由于 Spring MVC 中基于 基于 URL(URL 后缀)的内容协商而发生的。
什么是内容协商?
在某些情况下,我们必须处理控制器返回的相同数据的多个表示(或视图)。确定要返回的数据格式称为内容协商。
内容协商如何运作?
通过 HTTP 发出请求时,可以通过设置 Accept
标头属性来指定您想要的响应类型。然而,浏览器实际上会发送非常混乱的Accept
标头,这使得依赖它们变得不切实际。因此 Spring 为内容协商提供了一些替代约定。
Spring Content Negotiation Alternatives - URL 后缀和/或 URL 参数
这些与
Accept
标头一起使用。结果, 可以通过三种方式中的任何一种来请求内容类型。默认情况下,他们 按此顺序检查:在 URL 中添加路径扩展名(后缀)。因此,如果传入的 URL 类似于http://myserver/myapp/accounts/list.html,那么 HTML 是必须的。对于电子表格,URL 应该是 http://myserver/myapp/accounts/list.xls。媒体类型的后缀 映射是通过 JavaBeans Activation 自动定义的 框架或 JAF(所以
activation.jar
必须在类路径上)。这样的 URL 参数:http://myserver/myapp/accounts/list?format=xls。的名称 参数默认为格式,但可以更改。用一个 参数默认禁用,但启用时,它被选中 第二个。
最后检查了Accept
HTTP 标头属性。这就是 HTTP 实际定义的工作方式,但是,如前所述,它可以 使用起来有问题。
在问题中解释的上述案例中,您看到的是基于路径扩展的内容协商在起作用。 (.au)
来自ContentNegotiationConfigurer的哈瓦文档,
favorPathExtension
公共 ContentNegotiationConfigurer 偏爱路径扩展(布尔 喜欢路径扩展)
是否应该使用 URL 路径中的路径扩展来确定 请求的媒体类型。
默认设置为 true,在这种情况下请求 /hotels.pdf 将被解释为对“application/pdf”的请求,无论 “接受”标头。
解决方案 - 将喜爱路径扩展设置为 false
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer)
configurer.favorPathExtension(false).
favorParameter(true).
parameterName("mediaType").
ignoreAcceptHeader(true).
useJaf(false).
defaultContentType(MediaType.APPLICATION_JSON).
mediaType("xml", MediaType.APPLICATION_XML).
mediaType("json", MediaType.APPLICATION_JSON);
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false" />
<property name="favorParameter" value="true" />
<property name="parameterName" value="mediaType" />
<property name="ignoreAcceptHeader" value="true"/>
<property name="useJaf" value="false"/>
<property name="defaultContentType" value="application/json" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
</bean>
请注意,除了将喜爱路径扩展设置为 false 之外,上述配置还有一些其他更改。
更多详情请见here。
为了补全,我们得到的问题回复如下。
"timestamp": 1518691842254,
"status": 406,
"error": "Not Acceptable",
"exception": "org.springframework.web.HttpMediaTypeNotAcceptableException",
"message": "Not Acceptable",
"path": "/rest/token/something.au"
【讨论】:
【参考方案2】:我认为它在序列化器和反序列化器时由 A 数据传输对象 (DTO) 引起。所以用户应该实现 Serializable 接口。
【讨论】:
【参考方案3】:我遇到了类似的问题。我的资源映射到 /upload/( 需要文件路径)。所以资源 URI 会像 /upload/a/b/c/test1.jpg、upload/xy/test2.xml 等,
就像@Rajind 提到的那样,它将媒体类型视为 URL 中存在的扩展名(在点 (.) 之后)。
HTTP 状态 406 – 不可接受
"timestamp": 1538992653298,
"status": 406,
"error": "Not Acceptable",
"message": "Could not find acceptable representation",
"path": "/file-manager-services/api-6.0/234833/upload/Mohan/tst.jpg"
我通过添加以下配置解决了它。
@Configuration
@EnableWebMvc
public class **** implements WebMvcConfigurer
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer)
configurer.favorPathExtension(false);
....
....
【讨论】:
以上是关于以 .au 结尾的 URI 上的 Spring 更改媒体类型的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Azure AD 为应用服务上的 Spring Boot 应用设置重定向 URI
配置 Spring Security 5 Oauth 2 以使用 access_token uri 参数
为啥当参数以(.pl)结尾时,Spring MVC @RequestMapping 会为映射(/user/username:.+)抛出 406 错误
为啥 Spring MVC 以 404 响应并报告“No mapping found for HTTP request with URI [...] in DispatcherServlet”?