refactor(network): 优化网络请求日志记录功能

- 移除Headers导入,添加MultipartBody导入
- 重构logRequest方法,分离日志构建逻辑
- 新增buildRequestLog方法处理请求日志构建
- 新增buildRequestParamsLog方法处理不同请求参数的日志格式化
- 添加GET请求查询参数转换为JSON格式的功能
- 实现multipart表单数据转换为JSON格式的逻辑
- 添加JSON字符串转义功能避免特殊字符问题
- 重构multipartBodyToString方法处理表单字段提取
- 新增mapToJson和escapeJson工具方法
这个提交包含在:
徐勤民 2026-04-21 18:56:57 +08:00
父节点 9e5f68c320
当前提交 3eda1f1305

查看文件

@ -5,8 +5,8 @@ import com.xuqm.base.common.SHARE_UESR_TOKEN
import com.xuqm.base.extensions.getStringForPreferences import com.xuqm.base.extensions.getStringForPreferences
import com.xuqm.base.extensions.log import com.xuqm.base.extensions.log
import com.xuqm.base.extensions.loge import com.xuqm.base.extensions.loge
import okhttp3.Headers
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.MultipartBody
import okhttp3.RequestBody import okhttp3.RequestBody
import okhttp3.Response import okhttp3.Response
import okio.Buffer import okio.Buffer
@ -81,21 +81,53 @@ class HeaderInterceptor(val context: Context) : Interceptor {
} }
private fun logRequest(request: okhttp3.Request) { private fun logRequest(request: okhttp3.Request) {
val requestBodyText = request.body?.let { bodyToString(it) }.orEmpty() buildRequestLog(request).loge()
buildString { }
private fun buildRequestLog(request: okhttp3.Request): String {
return buildString {
append("request: ") append("request: ")
append(request.method) append(request.method)
append(" ") append(" ")
append(request.url) append(request.url)
append('\n') val params = buildRequestParamsLog(request)
append("headers: ") if (params.isNotBlank()) {
append(request.headers)
if (requestBodyText.isNotBlank()) {
append('\n') append('\n')
append("body: ") append("body: ")
append(requestBodyText) append(params)
}
}
}
private fun buildRequestParamsLog(request: okhttp3.Request): String {
if (request.method == "GET") {
return urlQueryToJson(request.url)
}
val body = request.body ?: return ""
if (request.method != "POST") {
return bodyToString(body)
}
return when (body) {
is MultipartBody -> multipartBodyToString(body)
else -> bodyToString(body)
}
}
private fun urlQueryToJson(url: okhttp3.HttpUrl): String {
if (url.querySize == 0) return ""
return buildString {
append("{")
repeat(url.querySize) { index ->
if (index > 0) append(",")
append("\"")
append(escapeJson(url.queryParameterName(index)))
append("\":")
append("\"")
append(escapeJson(url.queryParameterValue(index).orEmpty()))
append("\"")
}
append("}")
} }
}.loge()
} }
private fun bodyToString(requestBody: RequestBody): String { private fun bodyToString(requestBody: RequestBody): String {
@ -108,7 +140,38 @@ class HeaderInterceptor(val context: Context) : Interceptor {
} }
} }
private fun bodyHasUnknownEncoding(headers: Headers): Boolean { private fun multipartBodyToString(body: MultipartBody): String {
val formFields = linkedMapOf<String, String>()
body.parts.forEach { part ->
val disposition = part.headers?.get("Content-Disposition").orEmpty()
val name = disposition.substringAfter("name=\"", "").substringBefore('"')
if (name.isBlank()) return@forEach
if ("filename=\"" in disposition) {
return@forEach
}
val value = bodyToString(part.body).trim()
formFields[name] = value
}
return mapToJson(formFields)
}
private fun mapToJson(fields: Map<String, String>): String {
if (fields.isEmpty()) return "{}"
return fields.entries.joinToString(prefix = "{", postfix = "}") {
"\"${escapeJson(it.key)}\":\"${escapeJson(it.value)}\""
}
}
private fun escapeJson(value: String): String {
return value
.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t")
}
private fun bodyHasUnknownEncoding(headers: okhttp3.Headers): Boolean {
val contentEncoding = headers["Content-Encoding"] val contentEncoding = headers["Content-Encoding"]
return (contentEncoding != null && !contentEncoding.equals("identity", ignoreCase = true) return (contentEncoding != null && !contentEncoding.equals("identity", ignoreCase = true)
&& !contentEncoding.equals("gzip", ignoreCase = true)) && !contentEncoding.equals("gzip", ignoreCase = true))