OkDownload下载异常ResumeFailedException: Resume failed because of RESPONSE_PRECONDITION_FAILED
异常log日志
com.liulishuo.okdownload.core.exception.ResumeFailedException: Resume failed because of RESPONSE_PRECONDITION_FAILED
at com.liulishuo.okdownload.core.download.DownloadStrategy$ResumeAvailableResponseCheck.inspect(DownloadStrategy.java:297)
at com.liulishuo.okdownload.core.interceptor.connect.HeaderInterceptor.interceptConnect(HeaderInterceptor.java:103)
at com.liulishuo.okdownload.core.download.DownloadChain.processConnect(DownloadChain.java:215)
at com.liulishuo.okdownload.core.interceptor.BreakpointInterceptor.interceptConnect(BreakpointInterceptor.java:48)
at com.liulishuo.okdownload.core.download.DownloadChain.processConnect(DownloadChain.java:215)
at com.liulishuo.okdownload.core.interceptor.RetryInterceptor.interceptConnect(RetryInterceptor.java:40)
at com.liulishuo.okdownload.core.download.DownloadChain.processConnect(DownloadChain.java:215)
at com.liulishuo.okdownload.core.download.DownloadChain.start(DownloadChain.java:180)
at com.liulishuo.okdownload.core.download.DownloadChain.run(DownloadChain.java:247)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
原因:
可能是请求header中缺少If-Modified-Since
注: Last-Modified 与If-Modified-Since 都是标准的HTTP请求头标签,用于记录页面的最后修改时间。
解决方案
排除"If-Match"请求头
OkDownload初始化
OkDownload.setSingletonInstance(new OkDownload.Builder(this)
.connectionFactory(new NoEtagConnection.Factory())
.build());
NoEtagConnection
class NoEtagConnection private constructor(
private val client: OkHttpClient,
private val requestBuilder: Request.Builder
) : DownloadConnection, Connected {
private var request: Request? = null
var response: Response? = null
private constructor(client: OkHttpClient, url: String) : this(
client,
Request.Builder().url(url)
)
override fun addHeader(name: String, value: String) {
if ("If-Match" == name) {
return
}
requestBuilder.addHeader(name, value)
}
@Throws(IOException::class)
override fun execute(): Connected {
request = requestBuilder.build().apply {
response = client.newCall(this).execute()
}
return this
}
override fun release() {
response?.close()
request = null
response = null
}
override fun getRequestProperties(): Map<String, List<String>> = request?.headers?.toMultimap()
?: let { requestBuilder.build().headers.toMultimap() }
override fun getRequestProperty(key: String): String? =
request?.header(key) ?: requestBuilder.build().header(key)
@Throws(IOException::class)
override fun getResponseCode(): Int =
response?.code ?: throw IOException("Please invoke execute first!")
@Throws(IOException::class)
override fun getInputStream(): InputStream = (response?.let {
it.body ?: throw IOException("no body found on response!")
} ?: throw IOException("Please invoke execute first!")).byteStream()
@Throws(ProtocolException::class)
override fun setRequestMethod(method: String): Boolean {
requestBuilder.method(method, null)
return true
}
override fun getResponseHeaderFields(): Map<String, List<String>>? =
response?.headers?.toMultimap()
override fun getResponseHeaderField(name: String): String? = response?.header(name)
override fun getRedirectLocation(): String? {
val priorRes = response?.priorResponse
return priorRes?.let {
if (response?.isSuccessful == true && RedirectUtil.isRedirect(it.code)) response?.request?.url.toString() else null
}
}
class Factory : DownloadConnection.Factory {
private var clientBuilder: OkHttpClient.Builder? = null
fun setBuilder(builder: OkHttpClient.Builder?): Factory {
clientBuilder = builder
return this
}
fun builder(): OkHttpClient.Builder {
return clientBuilder ?: OkHttpClient.Builder()
}
@Throws(IOException::class)
override fun create(url: String): DownloadConnection {
return NoEtagConnection(builder().build(), url)
}
}
}