使用 Square 的 OkHttp https://github.com/square/okhttp,我该怎么做:
理想情况下,每次请求时都会自动存储、重新发送和更新 cookie。
对于 OkHttp3,一个简单的接受所有、非持久的
CookieJar
实现可以如下:
OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(new CookieJar() {
private final HashMap<HttpUrl, List<Cookie>> cookieStore = new HashMap<>();
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
cookieStore.put(url, cookies);
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
List<Cookie> cookies = cookieStore.get(url);
return cookies != null ? cookies : new ArrayList<Cookie>();
}
})
.build();
或者,如果您更喜欢使用
java.net.CookieManager
,请在您的项目中包含 okhttp-urlconnection
,其中包含 JavaNetCookieJar
,一个委托给 java.net.CookieHandler
的包装类:
dependencies {
compile "com.squareup.okhttp3:okhttp:3.0.0"
compile "com.squareup.okhttp3:okhttp-urlconnection:3.0.0"
}
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(new JavaNetCookieJar(cookieManager))
.build();
参见hidro的回答
您可以将 CookieHandler 传递给您的 OkHttpClient 实例。您可以使用 java.net 中的 CookieManager 实现,或者如果您愿意,也可以实现您自己的。选择最适合您需求的政策。
OkHttpClient client = new OkHttpClient();
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
client.setCookieHandler(cookieManager);
OkHttp将从Responses接收到的cookie保存到CookieHandler中,并在发送请求时从中读取。它将这样做以匹配请求/响应 URI。
我需要共享默认的 Cookie Jar (CookieManager.getInstance()),所以这对我来说似乎没问题。
return new CookieJar() {
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
CookieManager cookieManager = CookieManager.getInstance();
for (Cookie cookie : cookies) {
cookieManager.setCookie(url.toString(), cookie.toString());
}
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
CookieManager cookieManager = CookieManager.getInstance();
List<Cookie> cookies = new ArrayList<>();
if (cookieManager.getCookie(url.toString()) != null) {
String[] splitCookies = cookieManager.getCookie(url.toString()).split("[,;]");
for (int i=0; i<splitCookies.length; i++) {
cookies.add(Cookie.parse(url, splitCookies[i].trim()));
}
}
return cookies;
}
};
这里我如何实现 android 棒棒糖 - 提拉米苏以及 jvm 和非持久连接的 cookie 处理。
import android.content.Context
import android.webkit.WebView
import okhttp3.Cookie
import okhttp3.CookieJar
import okhttp3.HttpUrl
import java.net.CookieHandler
import java.net.CookiePolicy
import java.net.HttpCookie
/**
* android webkit webview cookie manager.
* [FULL USAGES](https://dimaslanjaka.github.io/2024/03/okhttp-cookie-handling-on-android.html)
*
* @author Dimas Lanjaka <a href="https://www.webmanajemen.com">https://www.webmanajemen.com</a>
*/
open class WebkitCookieManager : CookieJar {
/**
* support for below android 10
*/
private var webkitCookieManager: android.webkit.CookieManager? = null
/**
* support for jvm or android 10+
*/
private var javaCookieManager: java.net.CookieManager? = null
/**
* support for webview intercept connection cookie handling
*/
private var webview: WebView? = null
/**
* the android context for clearing cookies on non-webview instance
*/
private var context: Context? = null
/**
* for non-persistent cookies
*/
private val cookieStore = mutableMapOf<HttpUrl, List<Cookie>>()
/**
* construct android cookie manager without webview
*/
constructor(manager: android.webkit.CookieManager, ctx: Context? = null) {
webkitCookieManager = manager
setupAndroidCookieManager()
this.context = ctx
}
/**
* construct android cookie manager with webview
*/
constructor(manager: android.webkit.CookieManager, webView: WebView, ctx: Context? = null) {
webkitCookieManager = manager
setupAndroidCookieManager(webView)
this.webview = webView
this.context = ctx
}
/**
* construct non-persistent cookie manager
*/
constructor(ctx: Context? = null) {
this.context = ctx
}
/**
* construct java cookie manager
*/
constructor(manager: java.net.CookieManager, ctx: Context? = null) {
manager.setCookiePolicy(CookiePolicy.ACCEPT_ALL)
javaCookieManager = manager
CookieHandler.setDefault(javaCookieManager)
this.context = ctx
}
/**
* make android webkit cookie manager accept third-party cookies
*/
private fun setupAndroidCookieManager(webView: WebView? = null) {
webkitCookieManager?.setAcceptCookie(true);
if (webView != null) webkitCookieManager?.setAcceptThirdPartyCookies(webView, true);
}
/**
* save cookies after request finished
*/
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
cookies.forEach { cookie ->
webkitCookieManager?.setCookie(url.toString(), cookie.toString())
javaCookieManager?.cookieStore?.add(url.toUri(), HttpCookie.parse(cookie.toString())[0])
}
cookieStore.put(url, cookies);
}
/**
* load cookies before okhttp execute request {@link okhttp3.OkHttpClient#newCall(request)}
*/
override fun loadForRequest(url: HttpUrl): List<Cookie> {
return if (webkitCookieManager != null) {
// get from android webkit cookie manager
when (val cookies = webkitCookieManager?.getCookie(url.toString())) {
null -> emptyList()
else -> cookies.split("; ").mapNotNull { Cookie.parse(url, it) }
}
} else if (javaCookieManager != null) {
// get from java cookie manager
when (val cookies = javaCookieManager?.cookieStore?.cookies) {
null -> emptyList()
else -> cookies.toString().split("; ").mapNotNull { Cookie.parse(url, it) }
}
} else {
// get from non-persisten cookie store
val cookies = cookieStore[url]
return cookies ?: ArrayList()
}
}
/**
* clear all stored cookies everywhere
*/
fun clearCookies() {
// remove non-persistent stored cookies
cookieStore.clear()
// initialize android webkit cookie manager on null
if (webkitCookieManager == null) {
webkitCookieManager = android.webkit.CookieManager.getInstance()
setupAndroidCookieManager()
}
// indicator when webview not initialized
var standaloneWebview = false
// initalize fake webview instance
if (webview == null && context != null) {
// declare standalone webview
webview = WebView(context!!)
// treat as standalone webview
standaloneWebview = true
}
// remove all stored cookies from android webkit cookie manager
webkitCookieManager?.removeAllCookies(null)
webkitCookieManager?.flush()
webkitCookieManager?.removeSessionCookies(null);
// clear all caches from webview
webview?.clearCache(true)
webview?.clearHistory()
webview?.clearFormData();
webview?.clearSslPreferences();
if (standaloneWebview) {
// destroy standalone webview
webview?.destroy()
webview = null
}
// initialize java cookie manager
if (javaCookieManager == null) {
javaCookieManager = java.net.CookieManager(null, CookiePolicy.ACCEPT_ALL)
java.net.CookieHandler.setDefault(javaCookieManager)
}
// remove all stored cookies from java cookie manager
javaCookieManager?.cookieStore?.removeAll()
}
}
我在视图绑定 webview + 自定义 webviewclient 中使用 okhttp 进行拦截
val clientBuilder = OkHttpClient.Builder()
clientBuilder.cookieJar(WebkitCookieManager(CookieManager.getInstance(), binding!!webview, applicationContext))
这项工作并经过测试,当我清除 cookie 时,网站上 cookie 的值发生了变化,否则在 cookie 过期之前都保持不变。