使用OkHttpClient.Builder的cookieJar时出现HttpCookie空指针异常
在配置OkHttpClient.Builder的cookieJar时触发java.lang.NullPointerException,异常原因不明确,只能通过重新安装应用解决。错误堆栈如下:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.net.HttpCookie.getPath()' on a null object reference at java.net.CookieManager.pathMatches(CookieManager.java:395) at java.net.CookieManager.get(CookieManager.java:217) at okhttp3.JavaNetCookieJar.loadForRequest(JavaNetCookieJar.java:59) at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:84) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142) at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:88) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117) at com.my.app.data.networking.ApiLogger.datadogLogger$lambda$0(ApiLogger.kt:60) at com.my.app.data.networking.ApiLogger.$r8$lambda$IVB96D3u4ArgZv68i0G_W_fF2P0(Unknown Source:0) at com.my.app.data.networking.ApiLogger$$ExternalSyntheticLambda0.intercept(Unknown Source:2) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117) at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:225) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117) at com.my.app.di.module.RemoteModule.provideOkHttpClient$lambda$1(RemoteModule.kt:72) at com.my.app.di.module.RemoteModule.$r8$lambda$JrHU6JXY7kX0VmaQ0CHUwiu2oyI(Unknown Source:0) at com.my.app.di.module.RemoteModule$$ExternalSyntheticLambda0.intercept(Unknown Source:0) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117) at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:229) at okhttp3.RealCall.execute(RealCall.java:81) at retrofit2.OkHttpCall.execute(OkHttpCall.java:204) at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:46) at io.reactivex.Observable.subscribe(Observable.java:12284) at retrofit2.adapter.rxjava2.BodyObservable.subscribeActual(BodyObservable.java:35) at io.reactivex.Observable.subscribe(Observable.java:12284) at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96) at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:608) at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66) at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) at java.lang.Thread.run(Thread.java:764)
异常原因分析
从堆栈轨迹可以定位到:异常发生在系统CookieManager的pathMatches方法中,尝试调用HttpCookie.getPath()时,该HttpCookie实例为null。
根源是系统CookieManager的CookieStore中存储了null的HttpCookie对象,当OkHttp的JavaNetCookieJar在为请求加载Cookie时,会遍历CookieStore中的所有Cookie,遇到null对象就触发空指针。
可能的触发场景:
- 手动向CookieManager添加Cookie时,未做非空校验,插入了null值
- 解析响应头的Set-Cookie字段时,生成了无效的null Cookie(比如Cookie格式不规范,但解析逻辑未过滤)
- 应用重启时,Cookie持久化/恢复过程中数据损坏,导致恢复出null的Cookie实例
修复方案
1. 过滤null Cookie(快速修复)
在所有向CookieManager添加Cookie的逻辑中,增加非空判断,避免插入null值:
// 示例:解析Set-Cookie头并添加 val setCookieHeaders = response.headers("Set-Cookie") val uri = request.url.toUri() setCookieHeaders.forEach { header -> HttpCookie.parse(header)?.forEach { cookie -> cookie?.let { cookieManager.cookieStore.add(uri, it) } } }
2. 自定义SafeCookieJar替换JavaNetCookieJar
实现OkHttp的CookieJar接口,主动过滤null Cookie,避免依赖系统CookieManager的潜在问题:
class SafeCookieJar(private val cookieStore: CookieStore) : CookieJar { override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) { val uri = url.toUri() cookies.forEach { okHttpCookie -> val httpCookie = HttpCookie(okHttpCookie.name, okHttpCookie.value).apply { domain = okHttpCookie.domain path = okHttpCookie.path expires = okHttpCookie.expiresAt secure = okHttpCookie.secure httpOnly = okHttpCookie.httpOnly } cookieStore.add(uri, httpCookie) } } override fun loadForRequest(url: HttpUrl): List<Cookie> { val uri = url.toUri() return cookieStore.get(uri) .filterNotNull() // 关键:过滤所有null的HttpCookie .map { httpCookie -> Cookie.Builder() .name(httpCookie.name) .value(httpCookie.value) .domain(httpCookie.domain) .path(httpCookie.path) .expiresAt(httpCookie.expires) .secure(httpCookie.secure) .httpOnly(httpCookie.httpOnly) .build() } } }
配置OkHttpClient时使用自定义CookieJar:
val cookieManager = CookieManager() OkHttpClient.Builder() .cookieJar(SafeCookieJar(cookieManager.cookieStore)) // 其他配置项 .build()
3. 清理已损坏的Cookie(无需重装应用)
如果已经出现问题,可以在应用启动时主动清理CookieStore中的null Cookie:
val cookieManager = CookieManager() val targetUri = Uri.parse("https://your-api-domain.com") // 替换为你的API域名 val allCookies = cookieManager.cookieStore.get(targetUri) allCookies.filterIsNull().forEach { nullCookie -> cookieManager.cookieStore.remove(targetUri, nullCookie) }
4. 规范Cookie解析逻辑
确保解析Set-Cookie头时,只处理有效的Cookie对象,避免生成null实例:
fun parseValidCookies(header: String): List<HttpCookie> { return HttpCookie.parse(header)?.filterNotNull() ?: emptyList() }
内容的提问来源于stack exchange,提问作者RHS.Dev
相关产品推荐
相关产品推荐

