如何让Jersey Test / Client不填写默认的Accept标头?

时间:2016-12-01 00:54:36

标签: java jersey jersey-client jersey-test-framework

我试图以一种特殊的方式处理没有Accept标题的请求,但不管我做什么,泽西岛似乎一心想要填写一个,所以它总是看起来像请求有一个Accept标题,即使它没有。

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;

import static org.junit.Assert.assertEquals;

public class JerseyTestTest extends JerseyTest {

    @Path("hello")
    public static class HelloResource {
        @GET
        public String getHello(@Context HttpHeaders httpHeaders) {
            String acceptHeader = httpHeaders.getHeaderString(HttpHeaders.ACCEPT);
            return acceptHeader != null ? acceptHeader : "No Accept Header";
        }
    }

    @Override
    protected Application configure() {
        return new ResourceConfig(HelloResource.class);
    }

    @Test
    public void test() {
        final String hello = target("hello").request()
                .header(HttpHeaders.ACCEPT, null) // null means remove header
                .get(String.class);
        assertEquals("No Accept Header", hello);
    }
}

此测试结果为:

org.junit.ComparisonFailure: 
Expected :No Accept Header
Actual   :text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2

不知何故,Accept的默认text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2标头会在某处设置。它没有记录,我想知道如何禁用它。我查看了泽西岛的消息来源,但似乎找不到发生这种情况的原因或原因。

更新:当我使用curl命中没有Accept标头的端点时,没有生成的Accept标头,所以问题出现在Jersey Client或Jersey Test环境中。不知何故。

更新2:当使用默认的Grizzly2测试容器或JDK测试容器时,会出现此错误,但不会使用内存测试容器。

3 个答案:

答案 0 :(得分:0)

不确定这是否有助于其他人,但我们看到类似的行为,使用我们的客户端代码调用生产中的服务。我们正在使用Jersey 2.21.1。

扩展原帖中的代码,发现以下内容为真:

  • 如果Accept标头为空,则Jersey添加默认
  • 如果Accept标头为空String,则使用空的Accept标头
  • 如果Accept标头有值,则使用

我不确定是否有办法告诉Jersey在使用null时不要添加默认值。

public class JerseyAcceptHeaderTest extends JerseyTest {

    @Path("hello")
    public static class HelloResource {
        @GET
        public String getHello(@Context HttpHeaders httpHeaders) {
            String acceptHeader = httpHeaders.getHeaderString(HttpHeaders.ACCEPT);
            System.out.println("SERVER RECEIVED:" + acceptHeader);

            if (acceptHeader == null) {
                return "Null Accept Header";
            } else if (acceptHeader.equals("")) {
                return "No Accept Header";
            } else {
                return acceptHeader;
            }
        }
    }

    @Override
    protected Application configure() {
        return new ResourceConfig(HelloResource.class);
    }

    /**
     * this seems to be a bug in Jersey
     * it overrides a null Accept header
     */
    @Test
    public void test_accept_header_with_null() {
        final String acceptHeader = target("hello").request()
                .header(HttpHeaders.ACCEPT, null)
                .get(String.class);
        assertEquals("Null Accept Header", acceptHeader);
    }

    @Test
    public void test_accept_header_with_empty_string() {
        final String acceptHeader = target("hello").request()
                .header(HttpHeaders.ACCEPT, "")
                .get(String.class);
        assertEquals("No Accept Header", acceptHeader);
    }

    @Test
    public void test_accept_header_with_spaced_string() {
        final String acceptHeader = target("hello").request()
                .header(HttpHeaders.ACCEPT, "  ")
                .get(String.class);
        assertEquals("No Accept Header", acceptHeader);
    }

    @Test
    public void test_accept_header_with_value() {
        final String acceptHeader = target("hello").request()
                .header(HttpHeaders.ACCEPT, "application/json")
                .get(String.class);
        assertEquals("application/json", acceptHeader);
    }

}

答案 1 :(得分:0)

我现在正面临着同样的问题,经过一些研究,最终发现了问题。

WebResourceFactory.invoke(final Object proxy, final Method method, final Object[] {
    ...
    Invocation.Builder builder = newTarget.request()
            .headers(headers) // this resets all headers so do this first
            .accept(accepts); // if @Produces is defined, propagate values into Accept header; empty array is NO-OP
    ...
}

请求构建器会自动将API中指定的媒体类型( @Produce )添加到现有的标头中。可悲的是,我没有找到禁用该行为的方法。 因此,我将尝试扩展用于创建客户端的 WebResourceFactory 类(这是最终的),并覆盖该方法调用而不在请求生成器上调用accept

请注意,我不认为这是解决方案,而更多地是解决方法

[编辑] 由于WebResourceFactory是最终版本,因此我复制了它的内容,并删除了请求生成器上的 accept 调用。我有点难看,我知道并希望有人会找到更好的方法。

答案 2 :(得分:0)

我也实现了一种解决方法。如果将用于将Accept标头添加到标头列表的方法的输入:

public void accept(final String... types)

来自ClientRequest类,为空,我叫WebTarget.request()而不是WebTarget.request().accept(inputValue)

我认为,如果输入为null或为空字符串,则不应设置Accept标头。因此,我为此主题创建了一个@Jersey问题:https://github.com/eclipse-ee4j/jersey/issues/4407