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.log
import com.xuqm.base.extensions.loge
import okhttp3.Headers
import okhttp3.Interceptor
import okhttp3.MultipartBody
import okhttp3.RequestBody
import okhttp3.Response
import okio.Buffer
@ -81,21 +81,53 @@ class HeaderInterceptor(val context: Context) : Interceptor {
}
private fun logRequest(request: okhttp3.Request) {
val requestBodyText = request.body?.let { bodyToString(it) }.orEmpty()
buildString {
buildRequestLog(request).loge()
}
private fun buildRequestLog(request: okhttp3.Request): String {
return buildString {
append("request: ")
append(request.method)
append(" ")
append(request.url)
append('\n')
append("headers: ")
append(request.headers)
if (requestBodyText.isNotBlank()) {
val params = buildRequestParamsLog(request)
if (params.isNotBlank()) {
append('\n')
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 {
@ -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"]
return (contentEncoding != null && !contentEncoding.equals("identity", ignoreCase = true)
&& !contentEncoding.equals("gzip", ignoreCase = true))