7

我正在尝试以特定方式处理没有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它没有记录,我很想弄清楚如何禁用它。我查看了 Jersey 的源代码,但似乎无法找到发生这种情况的位置或原因。

更新:当我使用 curl 访问没有 Accept 标头的端点时,没有生成 Accept 标头,因此问题出在 Jersey 客户端或 Jersey 测试环境中,不知何故。

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

4

3 回答 3

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类(它是最终的),并覆盖该方法调用以不调用请求构建器上的接受

请注意,我不认为这是一种解决方案,而是一种解决方法

[编辑] 由于 WebResourceFactory 是最终的,我复制了它的内容并删除了请求构建器上的接受调用。有点难看,我知道并希望有人能找到更好的方法。

于 2019-10-10T09:48:58.007 回答
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

于 2020-03-10T13:02:26.723 回答
0

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

扩展原始帖子中的代码,发现以下内容是正确的:

  • 如果Acceptheader 为 null 则 Jersey 添加默认值
  • 如果Accept标头为空String,则使用空Accept标头
  • 如果Acceptheader 有一个值,则使用它

我不确定是否有办法告诉 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);
    }

}
于 2018-02-05T20:20:07.970 回答