首页 > 解决方案 > 使用存储在 persistentcookiejar 或其他容器中的 Cookie 来处理 android 中的 okhttp 请求

问题描述

这个问题基本上想知道如何使用存储的cookies进行后续请求。下面的长文只是举例。基本问题是如何对特定网站上的所有请求使用相同的 cookie。

基本上我试图在 android 应用程序中访问网站的登录页面。该网站的工作方式如下。

有 3 个网址需要考虑。

1 -> “ http://www.example.com/timeoutPage

2->“ http://www.example.com/mainPage

3->“ http://www.example.com/loginPage

要考虑的两个要点是

(1)如果我们直接去第三个url(loginPage),它会重定向到第一个url(timeoutPage)。timeoutPage 有一个按钮可以转到 mainPage。

(2) 如果我们转到第二个 url (mainPage),它会给我们一个 cookie。现在,在获取 cookie 后,当我们访问第三个 url (loginPage) 时,我们就可以访问它了。loginPage 有一个验证码,因此必须访问它(loginPage)才能登录。

如果没有在访问 2nd url(mainPage) 时给出的 cookie,我们将无法直接访问 3rd url(loginPage)。

所以我正在做的是制作一个ClearableCookieJar 并将其附加到 OkHttpClient。

OkHttpClient client;
ClearableCookieJar cookieJar;
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
cookieJar = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(this));
client = new OkHttpClient.Builder()
                .cookieJar(cookieJar)
                .build();
Request request = new Request.Builder()
                .url("http://www.example.com/mainPage")
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
                textView.setText("Failed to get response");
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if(response.isSuccessful()){
                    final String myResponse = response.body().string();
                    MainActivity.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            textView.setText(myResponse);
                        }
                    });
                }
            }
        });

一切都很好,因为我可以在我的 textview 中打印 mainPage 的 html。当我对 loginPage 发出另一个请求时,问题就从这里开始了。

request = new Request.Builder()
                .url("http://www.example.com/loginPage")
                .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0")
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
                textView.setText("Failed to get response");
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if(response.isSuccessful()){
                    final String myResponse2 = response.body().string();
                    MainActivity.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            textView.setText(myResponse2);
                        }
                    });
                }
            }
        });

在这里,我再次向 loginPage 发出请求,但我到达了 timeoutPage。我应该如何请求 loginPage url,以便我的请求在向 mainPage 发出请求时发送我存储在 cookieJar 中的 cookie。我想到的一种方法是

request = new Request.Builder()
                .url("http://www.example.com/loginPage")
                .addHeader("Cookie", cookieStringGivenAtMainPage)
                .build();

但我不知道如何访问该 cookieStringGivenAtMainPage。我应该如何到达该 loginPage?

我打印响应的 html,看看我是否到达了正确的页面。

标签: androidredirectcookiessession-cookiesokhttp

解决方案


看来您想知道的答案是单例模式。请参考下面的示例代码。大约 3 年前,我从 kakao 开发者网站获得了它。

    public class NetworkManager {

    private static NetworkManager instance;

    private OkHttpClient client;

    /**
     * By using Singleton Pattern we can share cookie, client values.
     **/

    private NetworkManager() {

        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        Context context = GlobalApplication.getGlobalApplicationContext();

        ClearableCookieJar cookieJar = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(context));
        builder.cookieJar(cookieJar);

        builder.followRedirects(true);
        builder.addInterceptor(new RedirectInterceptor());

        File cacheDir = new File(context.getCacheDir(), "network");

        if (!cacheDir.exists()) {
            cacheDir.mkdir();
        }

        Cache cache = new Cache(cacheDir, 10 * 1024 * 1024);
        builder.cache(cache);

        builder.connectTimeout(30, TimeUnit.SECONDS);
        builder.readTimeout(10, TimeUnit.SECONDS);
        builder.writeTimeout(10, TimeUnit.SECONDS);

        client = builder.build();
    }

    public static NetworkManager getInstance() {
        if (instance == null) {
            instance = new NetworkManager();
        }
        return instance;
    }

    public OkHttpClient getClient() {
        return client;
    }
}

此外,下面是示例用法。

OkHttpClient client = NetworkManager.getInstance().getClient();

RequestBody formBody = new FormBody.Builder()
        .add("userId", getTargetUserId())
        .build();

Request request = new Request.Builder()
        .url("www.test.com/insert.php")
        .post(formBody)
        .build();

client.newCall(request).enqueue(callback);

推荐阅读