8

I am using the Volley framework in a project where I always need to handle the redirects myself to handle the headers.

How redirects are handled depends right now on the method and the transport layer. I would like to use the defaults of Volley (automatic selection of the transport layer) without changing any Volley code.

A valid solution is to always use OkHttp as a transport layer (as mentioned in Issues and contribution for Volley), but I would like to know if there is a way without an additional framework.

Therefore I am looking for a "clean" way to disable automatic redirect handling.

Edit:

I prefer to use OkHttp so that I don't have to manage what version to use on what Android myself, but the solution provided by Itai Hanski is very good to, when wanting to change the transport layer behavior.

Community
  • 1
  • 1
Wicket
  • 393
  • 3
  • 8

4 Answers4

17

If you don't care about old APIs (< 9) and you just want volley stop following redirects you can do

RequestQueue requestQueue = Volley.newRequestQueue(context, new HurlStack() {
    @Override
    protected HttpURLConnection createConnection(URL url) throws IOException {
        HttpURLConnection connection = super.createConnection(url);
        connection.setInstanceFollowRedirects(false);

        return connection;
    }
});
  • 2
    after this changes i also had to make a change in BasicNetwork class, in method "performRequest" and change the IF statement to: if ((statusCode < 200 || statusCode > 299) && statusCode != 303), otherwise the method fires IOException. – Bugdr0id Jul 17 '15 at 07:31
  • 1
    @Bugdr0id can you please let me know the best way to override `BasicNetwok` class – Alireza Fattahi Dec 05 '17 at 06:27
7

I think A HttpStack implementation for Volley that uses OkHttp as its transport is the best solution

RequestQueue queue = Volley.newRequestQueue(this);

Network network = new BasicNetwork(new OkHttpStack());
RequestQueue queue = new RequestQueue(new DiskBasedCache(new File(getCacheDir(), "volley")), network);
queue.start();

OkHttpStack class:

public class OkHttpStack extends HurlStack {
private final OkHttpClient client;

public OkHttpStack() {
this(new OkHttpClient());
}

public OkHttpStack(OkHttpClient client) {
if (client == null) {
throw new NullPointerException("Client must not be null.");
}
this.client = client;
}

@Override protected HttpURLConnection createConnection(URL url) throws IOException {
return client.open(url);
}
}

Update: if you are using new version of okhttp stack then use

public class OkHttpStack extends HurlStack {
    private final OkUrlFactory mFactory;

    public OkHttpStack() {
        this(new OkHttpClient());
    }

    public OkHttpStack(OkHttpClient client) {
        if (client == null) {
            throw new NullPointerException("Client must not be null.");
        }
        mFactory = new OkUrlFactory(client);
    }

    @Override
    protected HttpURLConnection createConnection(URL url) throws IOException {
       return mFactory.open(url);
    }
}
Florian von Stosch
  • 1,700
  • 1
  • 14
  • 22
LOG_TAG
  • 19,894
  • 12
  • 72
  • 105
3

This solution doesn't require another framework:

Volley uses AndroidHTTPClient or Apache (if SDK level is 8 and under) by default. You could override / inherit the changes you want for redirection in these classes and create a custom HttpStack with them, feeding it to the Volley.newRequestQueue().

EDIT:

Assuming the very long named custom HttpStack implementations are yours:

HttpStack stack;
if (Build.VERSION.SDK_INT >= 9) {
    stack = new RedirectionHurlStack();
} else {
    stack = new RedirectionHttpClientStack();
}

sRequestQueue = Volley.newRequestQueue(context, stack);
Itai Hanski
  • 8,540
  • 5
  • 45
  • 65
  • In this solution I disable the automatic choosing of the best transportation layer and have to implement a switch myself, right? – Wicket Sep 17 '13 at 07:49
  • Just to clarify: this is a good solution, but I preferred the one with OkHttp over this. I will also write this in my Question. Thanks for your help! – Wicket Sep 18 '13 at 07:37
  • Hope that works out! I kind of thought you were looking for a solution not involving another 3rd party library – Itai Hanski Sep 18 '13 at 07:51
1

Try on more call with the Location value from the network response headers

Kotlin Implementation

fun fetchRemoteList(
    url: String,
    context: Context,
    callback: OnFetchListCompleted,
    firstTry: Boolean = true
) {
    val queue = Volley.newRequestQueue(context)
    val stringRequest = StringRequest(
        Request.Method.GET, url,
        Response.Listener { response ->
            GlobalScope.launch {
                callback.fetchListSucceed()
            }
        },
        Response.ErrorListener { error ->
            val locationRedirectUrl: String? = error?.networkResponse?.headers?.get("Location")

            if (firstTry && !locationRedirectUrl.isNullOrEmpty()) {
                fetchRemoteList(locationRedirectUrl, context, callback, false)
            } else {
                callback.fetchListFailed(error?.message ?: "")
            }
        })

    queue.add(stringRequest)
}
Moaz Rashad
  • 1,035
  • 1
  • 10
  • 16