Java Spring更改URI上的媒体类型,结尾为.au

Java Spring更改URI上的媒体类型,结尾为.au,java,spring,rest,content-type,Java,Spring,Rest,Content Type,当前实现了一个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 P

当前实现了一个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 microsystems制作的音频格式…),其中包含“blah”。 如果我在方法中随时检查用户名的值,我会得到正确的电子邮件地址,包括.au


我猜Spring堆栈中的某些东西正在解析.au并试图强制执行不同的媒体类型,因此现在它忽略了application/json,我认为这是在序列化程序和反序列化程序时从数据传输对象(DTO)引起的。所以用户应该实现可序列化的界面。

我最近遇到了同样的问题,并发现了这个问题。想在这里分享它,因为它会帮助其他人。@Patrick解释说,这种行为似乎是由于Spring MVC中基于URL(URL后缀)的内容协商而发生的

什么是内容协商?

在某些情况下,我们必须处理控制器返回的相同数据的多个表示(或视图)。确定返回哪种数据格式称为内容协商

内容协商是如何进行的?

通过HTTP发出请求时,可以通过设置
Accept
头属性来指定所需的响应类型。然而,浏览器实际上发送非常混乱的
Accept
标题,这使得依赖它们变得不切实际。因此,Spring为内容协商提供了一些替代约定

Spring内容协商备选方案-URL后缀和/或URL参数

它们与使用
Accept
标题一起工作。因此 可以通过三种方式中的任意一种请求内容类型。默认情况下,他们 按以下顺序进行检查:

  • 在URL中添加路径扩展名(后缀)。因此,如果传入的URL类似于HTML 是必需的。对于电子表格,URL应为 . 媒体类型的后缀 映射是通过JavaBeans激活自动定义的 框架或JAF(因此
    activation.jar
    必须在类路径上)

  • 类似以下内容的URL参数:。名称 默认情况下,参数为format,但这可能会更改。使用 默认情况下,参数处于禁用状态,但启用后,将选中该参数 第二

    • 最后,检查
      Accept
      HTTP头属性。HTTP实际上就是这样定义的,但正如前面提到的,它可以 使用起来可能有问题
在问题中解释的上述案例中,您看到的是基于路径扩展的内容协商。(.au

来自哈瓦大学的

favorPathExtension

公共内容协商配置器favorPathExtension(布尔值 favorPathExtension)

是否应使用URL路径中的路径扩展来确定 请求的媒体类型

默认情况下,此设置为true,在这种情况下,请求/hotels.pdf 将被解释为请求“application/pdf”,无论 “接受”标题

解决方案-将favorPathExtension设置为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>

我面临着类似的问题。我的资源映射到/upload/需要文件路径)。因此,资源URI将类似于/upload/a/b/c/test1.jpg、upload/xy/test2.xml等

正如@Rajind所提到的,它将媒体类型视为URL中的扩展(在点(.)之后)

HTTP状态406–不可接受

我通过添加下面的配置解决了这个问题

@Configuration
@EnableWebMvc
public class **** implements WebMvcConfigurer {

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {

        configurer.favorPathExtension(false);
    }

....
....

}
{
    "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);
    }

....
....

}