Spring在最后用.au更改媒体类型

时间:2016-12-21 12:17:44

标签: 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 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

3 个答案:

答案 0 :(得分:2)

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

什么是内容协商?

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

内容协商如何运作?

通过HTTP发出请求时,可以通过设置Accept标头属性来指定您想要的响应类型。但是,浏览器实际上会发送非常令人困惑的Accept标头,这使得依赖它们变得不切实际。因此,Spring为内容协商提供了一些替代约定。

Spring内容协商替代方案 - 网址后缀和/或网址参数

  

这些与Accept标题的使用一起使用。结果,   可以通过三种方式中的任何一种来请求内容类型。默认情况下他们   按此顺序检查:

     
      
  • 在网址中添加路径扩展名(后缀)。因此,如果传入的URL类似于http://myserver/myapp/accounts/list.html,那么HTML   是必须的。对于电子表格,URL应该是   http://myserver/myapp/accounts/list.xls。媒体类型的后缀   映射是通过JavaBeans Activation自动定义的   框架或JAF(所以activation.jar必须在类路径上)。

  •   
  • 这样的网址参数:http://myserver/myapp/accounts/list?format=xls。的名字   参数是默认格式,但可以更改。用一个   默认情况下禁用参数,但启用后,将检查该参数   第二

         
        
    • 最后检查Accept HTTP标头属性。这就是HTTP实际定义的工作方式,但是,如前所述,它可以   使用会有问题。
    •   
  •   

在问题中解释的上述情况中,您看到的是基于路径扩展的内容协商。 (的 .AU

来自ContentNegotiationConfigurer的hava文件,

  

favorPathExtension

     

public ContentNegotiationConfigurer favorPathExtension(boolean   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>

请注意,除了将favorPathExtension设置为false之外,上述配置还有一些其他更改。

有关详细信息,请访问here

为了完成,我们对此问题的回应如下:

{
  "timestamp": 1518691842254,
  "status": 406,
  "error": "Not Acceptable",
  "exception": "org.springframework.web.HttpMediaTypeNotAcceptableException",
  "message": "Not Acceptable",
  "path": "/rest/token/something.au"
}

答案 1 :(得分:0)

我认为它是由串行器和解串器时的A数据传输对象(DTO)引起的。所以用户应该实现Serializable接口。

答案 2 :(得分:0)

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

就像@Rajind提到的那样,它正在考虑将媒体类型作为URL中扩展名(在dot(。)之后)。

  

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

....
....

}