使用存储在 persistentcookiejar 或其他容器中的 Cookie 来处理 android 中的 okhttp 请求

Posted

技术标签:

【中文标题】使用存储在 persistentcookiejar 或其他容器中的 Cookie 来处理 android 中的 okhttp 请求【英文标题】:Use stored Cookie in persistentcookiejar or some other container for okhttp requests in android 【发布时间】:2020-06-03 19:09:56 【问题描述】:

这个问题基本上是想知道如何使用存储的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,看看我是否到达了正确的页面。

【问题讨论】:

【参考方案1】:

看来您想知道的答案是单例模式。 请参考下面的示例代码。大约 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);

【讨论】:

以上是关于使用存储在 persistentcookiejar 或其他容器中的 Cookie 来处理 android 中的 okhttp 请求的主要内容,如果未能解决你的问题,请参考以下文章

是否可以使用密钥保管库加密文件并使用“Azure 存储数据移动库”将其存储在存储帐户中

如何在Oracle中使用Java存储过程

我应该使用本地存储来存储用户数据吗

oracle中的存储过程,有啥作用,以及怎么在代码中使用?

如何在 React Native 中使用异步存储存储唯一数据?

如何使用存储在会话存储中的访问令牌使用 HttpClient 进行 Web api 调用?