改变Volley框架的重定向策略

8

我在一个项目中使用Volley框架,其中我始终需要自己处理重定向以处理头文件。

如何处理重定向取决于方法和传输层。我想使用Volley的默认设置(自动选择传输层),而不更改任何Volley代码。

一种有效的解决方案是始终使用OkHttp作为传输层(如Issues and contribution for Volley中所述),但我希望知道是否有一种不需要额外框架的方法。

因此,我正在寻找一种“干净”的方法来禁用自动重定向处理。

编辑:

我倾向于使用OkHttp,这样我就不必自己管理要在哪个Android上使用什么版本,但Itai Hanski提供的解决方案也非常好,当想要更改传输层行为时可以使用。

4个回答

17

如果您不关心旧的API(<9),并且只想让Volley停止重定向,您可以执行以下操作:

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
在这些更改之后,我还必须对BasicNetwork类中的"performRequest"方法进行更改,并将 IF 语句更改为: if ((statusCode < 200 || statusCode > 299) && statusCode != 303),否则该方法会触发 IOException。 - Bugdr0id
1
@Bugdr0id,你能告诉我覆盖BasicNetwork类的最佳方法吗? - Alireza Fattahi

7

我认为,一个使用OkHttp作为传输方式的Volley HttpStack实现 是最好的解决方案。

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类:

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

更新: 如果您正在使用最新版本的okhttp堆栈,请使用

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

有人知道OkHttp在旧版Android(2.2)上的可靠性如何吗?我找不到任何测试。 - Wicket
@Wicket OkHttp支持Android 2.2及以上版本。对于Java,最低要求为1.5 http://square.github.io/okhttp/ - LOG_TAG
1
OkHttpClient没有open方法。你自己的不同答案更准确:https://dev59.com/g2Af5IYBdhLWcg3wsUbT#24951835 - Denys Kniazhev-Support Ukraine
谢谢提醒!对于新的OkHttp堆栈,我们需要更改辅助类。 - LOG_TAG
2
对于那些不知道什么是OkUrlFactory的人,可以在gradle中添加以下依赖: compile 'com.squareup.okhttp:okhttp-urlconnection:1.6.0' - Adam Varhegyi

3

这个解决方案不需要另一个框架:

Volley默认使用AndroidHTTPClient或Apache(如果SDK级别为8及以下)。您可以覆盖/继承这些类中的重定向所需更改,并创建一个自定义HttpStack,将其提供给Volley.newRequestQueue()

编辑:

假设您拥有非常长命名的自定义HttpStack实现:

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

sRequestQueue = Volley.newRequestQueue(context, stack);

在这个解决方案中,我禁用了自动选择最佳传输层的功能,需要自己实现一个开关,对吗? - Wicket
只是想澄清一下:这是一个好的解决方案,但我更喜欢使用OkHttp。我也会在我的问题中写明这一点。感谢您的帮助! - Wicket
希望能解决问题!我有点认为你在寻找不涉及另一个第三方库的解决方案。 - Itai Hanski

1
尝试使用网络响应头中的位置值进行更多的调用。
Kotlin实现。
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)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接