You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Coil在Compose中加载含波斯语文件名图片时遇显示异常

解决Coil加载含波斯语/波斯数字文件名图片失败问题

问题现象

使用Coil的rememberAsyncImagePainter加载图片时,若响应头的Content-Disposition包含波斯语及波斯数字文件名(如تست۳_128.jpg),会抛出IllegalArgumentException异常,提示Unexpected char 0x62a in content-disposition value。

解决方案

问题根源是OkHttp默认解析Content-Disposition时仅支持ASCII字符,不兼容非ASCII文件名。通过自定义OkHttp拦截器修正响应头即可解决:

1. 编写自定义拦截器

可选两种处理方式:

方式一:移除filename参数(简单直接)

如果不需要保留文件名信息,直接移除Content-Disposition中的filename部分:

class FixContentDispositionInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val response = chain.proceed(chain.request())
        val contentDisposition = response.header("Content-Disposition") ?: return response
        
        // 只保留attachment; 部分,移除filename参数
        val fixedDisposition = contentDisposition.substringBefore("filename=").trimEnd(';')
        return response.newBuilder()
            .header("Content-Disposition", fixedDisposition)
            .build()
    }
}
方式二:编码非ASCII文件名(保留文件名)

按照RFC 5987标准对非ASCII文件名进行UTF-8编码,让OkHttp能正确解析:

import java.net.URLEncoder

class FixContentDispositionInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val response = chain.proceed(chain.request())
        val contentDisposition = response.header("Content-Disposition") ?: return response
        
        val filenameRegex = Regex("filename=\"([^\"]+)\"")
        val matchResult = filenameRegex.find(contentDisposition) ?: return response
        
        val originalFilename = matchResult.groupValues[1]
        // 编码为RFC 5987兼容格式
        val encodedFilename = "filename*=UTF-8''${URLEncoder.encode(originalFilename, "UTF-8")}"
        val fixedDisposition = contentDisposition.replace(filenameRegex, encodedFilename)
        
        return response.newBuilder()
            .header("Content-Disposition", fixedDisposition)
            .build()
    }
}

2. 配置Coil使用自定义OkHttp客户端

将拦截器添加到OkHttp客户端,并配置给Coil的ImageLoader:

val okHttpClient = OkHttpClient.Builder()
    .addInterceptor(FixContentDispositionInterceptor())
    .build()

val imageLoader = ImageLoader.Builder(context)
    .okHttpClient(okHttpClient)
    .build()

3. 在Compose中使用自定义ImageLoader

修改rememberAsyncImagePainter的参数,传入自定义的ImageLoader:

val a = rememberAsyncImagePainter(
    model = selfUser.imageUrl,
    contentScale = ContentScale.Crop,
    imageLoader = imageLoader,
    onSuccess = {
        Log.d("mohaTest", "HeaderAvatar:onSuccess")
    },
    onError = {
        Log.d("mohaTest", "HeaderAvatar: ${it.result.throwable}")
    }
)

原理说明

Coil底层依赖OkHttp处理网络请求,而OkHttp默认遵循RFC 2616规范,仅支持ASCII字符的文件名。通过拦截器修改响应头,要么移除导致解析失败的filename参数,要么将其编码为RFC 5987兼容的UTF-8格式,就能避免解析异常,正常加载图片。

内容的提问来源于stack exchange,提问作者Moha.AZ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 18:40:58