我想对每个请求进行全局检查。因此,我使用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"}
问题:
为什么回答不同?我该如何解决?
答案 0 :(得分:1)
似乎ContainerRequestFilter
的默认响应构建器不使用accept标头来覆盖响应内容类型。需要将内容类型添加到Response
throw new WebApplicationException(Response.status(422).type("application/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());
}
}
}
do_command
答案 1 :(得分:1)
基于@pedrofb好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());
}
}
}