19

I have an authentication call that i'm trying to make using Retrofit on Android. The call returns a 302 to either a success or failure page. The original 302 response brings back a session cookie needed to maintain authentication on success, however Retrofit is automatically handing the request off to the redirect url before I get a chance to consume the cookie.

Is there a way to prevent following the redirect? Or is there a way to write a response handler on Retrofit that can add the appropriate header before making the second call?

nak5ive
  • 1,963
  • 4
  • 15
  • 21

5 Answers5

16

to prevent the redirect you have to configure your client, e.g with OkHttp 2:

private sendRequest() {
    OkHttpClient client = new OkHttpClient();
    client.setFollowRedirects(false);

    connectAdapter = new RestAdapter.Builder()
            .setClient(new OkClient(client))
            .setEndpoint("http://yourendpoint")
            .setLogLevel(RestAdapter.LogLevel.FULL)
            .build();

    connectAdapter.create(YourRequest.class).sendMyRequest("login","password");

}

With OKHTTP 3/4 (you can read this answer from @gropapa):

OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.followRedirects(false);
OkHttpClient httpClient = builder.build();
Climbatize
  • 1,103
  • 19
  • 34
  • 1
    This causes retrofit to throw an error, rather than returning a response which has a 303. Is that expected behavior? – android_student Apr 19 '15 at 01:30
  • I dont't know, in my case the problem was a redirection that occurred on top of a 302. No error was thrown. What kind of error does retrofit throw in your case? – Climbatize Apr 20 '15 at 08:22
  • Hey i don't know if its still relevant but you can add a try catch arround and read the response from the exception. Sow until there is an other way not following redirects but still reading the response you can do it with the try catch. – Neristance May 18 '15 at 10:47
6

Event if the post is VERY old, here is my answer with OkHttp 3 just use the builder as the following

OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.followRedirects(false);
OkHttpClient httpClient = builder.build();

in a Response object (I use Retrofit actually), you'll find the redirect url in

response.headers.get("Location")

Hope this helps

gropapa
  • 577
  • 6
  • 10
2

I know this is an old post, maybe it will still help for someone. I have a similar problem, my solution was to add a redirectStrategy (http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/client/RedirectStrategy.html) to httpClient:

private static final RestAdapter REST_ADAPTER= new RestAdapter.Builder()
            .setEndpoint(HTTP_TEST_URL)
            .setClient(new ApacheClient(HttpClients.custom()
                .setRedirectStrategy(new RedirectStrategy() {
                    @Override
                    public boolean isRedirected(HttpRequest request, HttpResponse response,
                        HttpContext context) throws ProtocolException {
                        return response.getStatusLine().getStatusCode() == 302;
                    }

                    @Override
                    public HttpUriRequest getRedirect(HttpRequest request,
                        HttpResponse response, HttpContext context)
                        throws ProtocolException {

                        //String cookieValue = response.getFirstHeader("Set-Cookie").getValue();
                        String location = response.getFirstHeader("location").getValue();

                        HttpUriRequest request_= new HttpGet(location);
                        return request_;
                    }}).build()))
            .build();

With this I can get access to any (private) url. I think the cookie data added automatically. Maybe you should rewrite the getRedirect(), isRedirected() functions to pass your special needs.

0

I was in a similar situation to yours. Basically all we need is to capture the "Set-Cookie" header that your server returns before redirecting. This is how I handled it using OkHTTP:

final OkHttpClient client = new OkHttpClient();
CookieHandler handler = client.getCookieHandler();
CookieManager manager = new CookieManager();
handler.setDefault(manager);

//boilerplate:
RequestBody formData = new FormEncodingBuilder()
        .add("req_username", username)
        .add("req_password", password).build();
Request request = new Request.Builder().url(LOGIN_URL).post(formData).build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

// print our cookies:
List <HttpCookie> cookies = manager.getCookieStore().getCookies();
for(HttpCookie cookie : cookies) {
    Log.v(TAG, cookie.getName() + "=" + cookie.getValue());
}
VM4
  • 6,321
  • 5
  • 37
  • 51
0

I've edited my previous answer since you're most likely using a POST/PUT when calling your login rest api and OkHttp converts any non GET or HEAD request into a GET request before redirecting which would probably not work for you.

Currently the feature of disabling redirects is missing from OkHttp but I've submitted a pull request for it. If and when that pull request is accepted it should allow you to disable redirect giving you the opportunity to deal with this use case on your own for the time being.

Here's the pull request https://github.com/square/okhttp/pull/944

Miguel
  • 19,793
  • 8
  • 56
  • 46