Ktor Client处理application/x-gzip类型压缩XML文件的解压缩配置问题
Ktor Client处理application/x-gzip类型压缩XML文件的解压缩配置问题
嘿,我看你在纠结Ktor Client处理application/x-gzip类型的压缩XML文件时,怎么让它自动解压缩并解析的问题,刚好我之前也碰到过类似的情况,来给你梳理下解决方案!
首先得搞清楚问题出在哪:你配置的ContentEncoding插件,其实是用来处理**响应头带Content-Encoding: gzip**的传输编码场景,但这次服务器返回的是Content-Type: application/x-gzip——意思是整个响应体本身就是一个gzip压缩包,不是普通XML响应加个压缩头,所以ContentEncoding插件不会自动触发解压缩操作。
那该怎么调整呢?我们可以在XML解析的前置步骤里,手动先把gzip内容解压缩,再交给XML序列化器处理。下面是具体的修改方案:
1. 自定义能处理gzip解压缩的XML转换器
我们可以扩展ContentNegotiation的xmlGzip配置,让它先解压缩字节流再解析XML:
import io.ktor.client.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.xml.* import kotlinx.serialization.xml.* import io.ktor.http.* import io.ktor.util.io.* import java.util.zip.GZIPInputStream fun Configuration.xmlGzip( format: XML = DefaultXml, contentType: ContentType = ContentType("application", "x-gzip") ) { // 先拿到默认的XML转换器 val xmlConverter = KotlinxSerializationXmlConverter(format) // 给application/x-gzip类型注册自定义序列化逻辑 serialization(contentType) { // 定义解压缩逻辑:把gzip字节流转为普通字节流 suspend fun transformInput(charset: Charset, input: ByteReadChannel): ByteReadChannel { val compressedBytes = input.readRemaining().readBytes() val decompressedStream = GZIPInputStream(compressedBytes.inputStream()) return ByteReadChannel(decompressedStream.readBytes()) } // 反序列化时先解压缩,再用默认XML转换器解析 deserialize { charset, input -> val decompressedInput = transformInput(charset, input) xmlConverter.deserialize(charset, decompressedInput) } // 序列化逻辑沿用默认的XML即可(如果不需要发送gzip压缩的XML,不用改) serialize { contentType, value -> xmlConverter.serialize(contentType, value) } } }
2. 调整HttpClient的整体配置
接下来修改你的客户端配置,保留必要的插件同时,确保兼容普通XML和gzip压缩的XML响应:
fun getHttpXmlClient(timeout: Long = 1500): HttpClient = HttpClient { install(HttpTimeout) { requestTimeoutMillis = timeout connectTimeoutMillis = 1500 socketTimeoutMillis = 900 } // 保留ContentEncoding,处理带Content-Encoding头的普通压缩场景 install(ContentEncoding) { gzip() deflate() identity() } install(ContentNegotiation) { // 注册我们自定义的gzip+XML转换器 xmlGzip() // 同时保留普通XML转换器,兼容非压缩的XML响应 xml(DefaultXml) } install(DefaultRequest) { // 调整Accept头,明确告诉服务器我们接受application/x-gzip类型 headers.append("Accept", "application/xml, application/x-gzip, */*;q=0.8") headers.append("Accept-Encoding", "gzip, deflate") } }
额外的备选方案(手动处理)
如果你不想折腾自定义转换器,也可以手动接收字节流再解压缩解析,虽然不够优雅但胜在直观:
val client = getHttpXmlClient() val response = client.get("你的目标URL") // 先拿到压缩的字节数组 val compressedBytes = response.body<ByteArray>() // 手动解压缩 val decompressedBytes = GZIPInputStream(compressedBytes.inputStream()).readBytes() // 转成字符串后用XML解析器处理 val xmlContent = String(decompressedBytes, Charsets.UTF_8) // 后续就是你原本的XML解析逻辑
简单总结下核心逻辑:application/x-gzip是实体本身为压缩包,不是传输层的压缩编码,所以不能靠ContentEncoding插件自动处理,必须在XML解析前手动介入解压缩步骤,把压缩的字节流转成普通XML字节流再交给序列化器。
内容来源于stack exchange
相关产品推荐
相关产品推荐

