【问题标题】:ContainerRequestFilter returns wrong content type for entityContainerRequestFilter 为实体返回错误的内容类型
【发布时间】:2016-10-30 10:22:37
【问题描述】:

我想对每个请求进行全局检查。因此,如果检查未通过,我使用ContainerRequestFilter(不带@PreMatching)并抛出带有包含错误实体的响应的WebApplicationException

我的问题是,响应的内容类型与请求的 Accept 标头不匹配。但是,如果我在资源中抛出相同的异常,则响应包含正确的内容类型。

代码:

我的实体:

@XmlRootElement(namespace = "http://www.mycompany.com/test")
@XmlAccessorType(value = XmlAccessType.FIELD)
public class TestEntity {

    public TestEntity() {
        this.key = "error";
    }

    @XmlElement
    private String key;
}

我的过滤器:

@Named
public class TestFilter implements ContainerRequestFilter {
    private boolean globalError = true;

    public void filter(final ContainerRequestContext requestContext) throws IOException {
        if (globalError) {
            throw new WebApplicationException(Response.status(422).entity(new TestEntity()).build());
        }
    } 
}

我的资源:

@Named
public class TestResource {

    @GET
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public void find() {
        throw new WebApplicationException(Response.status(422).entity(new TestEntity()).build());
    }
}

我的 CXF 配置:

<jaxrs:server address="/rest/v1" id="test">
    <jaxrs:serviceBeans>
        <ref bean="testResource" />
    </jaxrs:serviceBeans>
    <jaxrs:providers>
        <bean class="org.apache.cxf.jaxrs.provider.JAXBElementProvider" />
        <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider" />
        <ref bean="testFilter" />
    </jaxrs:providers>
</jaxrs:server>

测试:

请求:

GET http://localhost:8080/test-webapp/services/rest/v1/ HTTP/1.1
Accept-Encoding: gzip,deflate
Accept: application/json
Host: localhost:8080
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)

回复globalError=true:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:testEntity xmlns:ns2="http://www.mycompany.com/test">
      <key>error</key>
</ns2:testEntity>

回复globalError=false:

{"key":"error"}

问题:

为什么反应不同?我该如何解决?

【问题讨论】:

    标签: java jackson jax-rs cxf


    【解决方案1】:

    似乎ContainerRequestFilter 的默认响应构建器不使用接受标头来覆盖响应内容类型。需要将内容类型添加到Response

    throw new WebApplicationException(Response.status(422).type("applicati‌​on/json").entity(new TestEntity()).build()
    

    获得所需行为的一个选项是在异常响应中设置 .type 之前检查标头(使用 requestContext.abortWith() 而不是引发异常)

    这是一个设置application/json的示例,如果它在标头中找到或返回默认类型

    public class TestFilter implements ContainerRequestFilter {
        private boolean globalError = true;
    
        private String typeFromHeaders(ContainerRequestContext requestContext){
            List<String> acceptHeaders = requestContext.getHeaders().get("Accept");
            if (acceptHeaders != null){         
                for (String acceptHeader: acceptHeaders){
                    if (acceptHeader.indexOf(MediaType.APPLICATION_JSON)>=0){
                        return MediaType.APPLICATION_JSON;
                    }   
                }
            }
            return null;
        }
        public void filter(final ContainerRequestContext requestContext) throws IOException {
            if (globalError) {
                requestContext.abortWith(
                        Response.status(422).type(typeFromHeaders(requestContext)).entity(new TestEntity()).build());
            }
        } 
    }
    

    【讨论】:

      【解决方案2】:

      基于@pedrofbgood answer,我发现使用ContainerRequestContext#getAcceptableMediaTypes 更容易解决:

      获取响应可接受的媒体类型列表。

      回报:
      根据 q 值排序的请求响应媒体类型的只读列表,优先级最高。

      我修改过的过滤器:

      @Named
      public class TestFilter implements ContainerRequestFilter {
          private boolean globalError = true;
      
          public void filter(final ContainerRequestContext requestContext) throws IOException {
              if (globalError) {
                  MediaType mediaType = requestContext.getAcceptableMediaTypes().size() > 0 ? requestContext.getAcceptableMediaTypes().get(0) : null;
                  throw new WebApplicationException(Response.status(422).type(mediaType).entity(new TestEntity()).build());
              }
          } 
      }
      

      【讨论】:

        猜你喜欢
        • 2012-12-18
        • 2020-11-14
        • 1970-01-01
        • 1970-01-01
        • 2012-12-04
        • 2021-04-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多