How do I get Jersey Test/Client to not fill in a d

2019-02-21 22:41发布

问题:

I'm trying to handle a request with no Accept header in a particular way, but Jersey seems hell-bent on filling one in, no matter what I do, so it always looks like the request has an Accept header, even if it doesn't.

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

This test results in:

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

Somehow there is a default Accept header of text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 that gets set somewhere. It's not documented, and I would love to figure out how to disable it. I've looked through the Jersey source, but can't seem to locate where this is happening or why.

Update: when I use curl to hit an endpoint without an Accept header, there is no generated Accept header, so the problem lies in Jersey Client or the Jersey Test environment, somehow.

Update 2: This bug exhibits when using the default Grizzly2 test container or the JDK test container, but NOT with the In Memory test container.

回答1:

Not sure if this helps anyone else but we were seeing similar behavior calling a service in production with our client code. We are using Jersey 2.21.1.

Expanded the code from the original post and found the following to be true:

  • if Accept header is null then Jersey adds the default
  • if Accept header is an empty String then an empty Accept header is used
  • if Accept header has a value it is used

I'm not sure if there is a way to tell Jersey not to add the default value when a null is used.

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

}