Jersey jax.rs client 2.5 follow redirect

2019-02-21 12:49发布

问题:

I have a setup where tomcat server hosting my REST servers redirects calls from HTTP (port 9080) to HTTPS ( port 9443 ).

I'm using jersey 2.5 implementation and cannot manage to configure the clients to follow redirections.

I've found this SO question( Jersey client doesn't follow redirects ), however it's provided for jersey 1.X series and the API has changed.

I've tried to adapt it for 2.5 with the following test code :

 SSLContextProvider ssl = new TrustAllSSLContextImpl(); // just trust all certs
 Response response  =     ClientBuilder.newBuilder()
     .sslContext(ssl.getContext()).newClient()
     .register(LoggingFilter.class)
     .target("http://testhost.domain.org:9080/rest.webapp/api/v1/hello/")
     .property(ClientProperties.FOLLOW_REDIRECTS, Boolean.TRUE)
     .request().get();   
 Assertions.assertThat(response.getStatus()).isNotEqualTo(302);

Which fails as the client does not seem to follow the redirections. Here is what the logging filter provides :

Feb 14, 2014 12:23:45 PM org.glassfish.jersey.filter.LoggingFilter log
INFO: 1 * Sending client request on thread main
1 > GET http://testhost.domain.org:9080/rest.webapp/api/v1/hello/

Feb 14, 2014 12:23:45 PM org.glassfish.jersey.filter.LoggingFilter log
INFO: 1 * Client response received on thread main
1 < 302
1 < Cache-Control: private
1 < Content-Length: 0
1 < Date: Fri, 14 Feb 2014 11:38:59 GMT
1 < Expires: Thu, 01 Jan 1970 01:00:00 CET
1 < Location: https://testhost.domain.org:9443/rest.webapp/api/v1/hello/
1 < Server: Apache-Coyote/1.1

From the jersey doc I understood that all that needs to be done is to add the ClientProperties.FOLLOW_REDIRECTS property to the client, but this obviously not to be the case.I've also found messages indicating that maybe a client side filter is required to follow the redirections, but found no examples or guidelines on this.

So if anyone having some experience with jax.rs and redirection could point me to some directions/docs/example code I'd really appreciate.

回答1:

correct way to do this is:

webTarget.property(ClientProperties.FOLLOW_REDIRECTS, Boolean.TRUE);


回答2:

Well I finally figured this out using a filter, not sure this is the best solution, any comments are appreciated :

public class FollowRedirectFilter implements ClientResponseFilter
{
   @Override
   public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException
   {
      if (responseContext.getStatusInfo().getFamily() != Response.Status.Family.REDIRECTION)
         return;

      Response resp = requestContext.getClient().target(responseContext.getLocation()).request().method(requestContext.getMethod());

      responseContext.setEntityStream((InputStream) resp.getEntity());
      responseContext.setStatusInfo(resp.getStatusInfo());
      responseContext.setStatus(resp.getStatus());
   }
}


回答3:

This happens because Http(s)UrlConnection doesn't follow redirect if URL scheme changes during the redirect. So the possible solution is to use alternative client transport connector.

This could look like

SSLContextProvider ssl = new TrustAllSSLContextImpl(); // just trust all certs

JerseyClientBuilder clientBuilder = new JerseyClientBuilder()
 .sslContext(ssl.getContext())
 .register(LoggingFilter.class);
clientBuilder.getConfiguration().connectorProvider(new org.glassfish.jersey.apache.connector.ApacheConnectorProvider());

JerseyClient client = clientBuilder.build();

Response response = client    
 .target("http://testhost.domain.org:9080/rest.webapp/api/v1/hello/")
 .property(ClientProperties.FOLLOW_REDIRECTS, Boolean.TRUE)
 .request().get();
Assertions.assertThat(response.getStatus()).isNotEqualTo(302);