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

REST分页数据获取咨询:响应合法性与Gson/Retrofit2解析方案

关于REST分页响应合法性与Gson+Retrofit2异常处理的解答

Great question! Let's tackle this from both practical and technical angles—since you're working on client-side dev with an unimplemented server, thinking about edge cases like invalid JSON upfront is really smart.

分页响应是否始终为合法JSON?

Short answer: No, you can't assume it will always be valid.

In an ideal world, well-designed REST APIs return strictly valid JSON for all responses (including pagination payloads like {"data": [...], "page": 1, "total": 100}). But in reality, there are plenty of scenarios where you might get invalid JSON:

  • Server-side bugs (e.g., typos in the JSON serializer, unhandled exceptions that dump raw error messages instead of structured JSON)
  • Network glitches that truncate the response body mid-transmission
  • Proxy servers or CDNs accidentally modifying the response content
  • Temporary maintenance pages returning HTML instead of JSON

So your client should always be prepared to handle invalid JSON responses, even for pagination endpoints.

用Gson + Retrofit2处理非法JSON的方案

By default, Retrofit's GsonConverterFactory will throw a JsonSyntaxException when it encounters invalid JSON, which will propagate to your callback or suspend function. Here are two robust approaches to handle this gracefully:

1. 用OkHttp Interceptor提前检查并处理响应

You can add an OkHttp interceptor to catch the raw response before it reaches Gson, validate the JSON, and either fix it (if feasible) or return a fallback response.

Example interceptor code:

class JsonValidationInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val response = chain.proceed(request)

        // Only apply to pagination endpoints (adjust path matching as needed)
        if (request.url.encodedPath.contains("/api/pagination")) {
            val rawBody = response.body?.string() ?: ""
            return try {
                // Attempt to parse with Gson to check validity
                Gson().fromJson(rawBody, JsonElement::class.java)
                // If valid, rebuild and return the original response
                response.newBuilder()
                    .body(rawBody.toResponseBody(response.body?.contentType()))
                    .build()
            } catch (e: JsonSyntaxException) {
                // Log the issue and return a fallback pagination response
                Log.e("JsonValidation", "Invalid JSON for ${request.url}: ${e.message}")
                val fallbackJson = """{"data": [], "page": 1, "total": 0}"""
                response.newBuilder()
                    .body(fallbackJson.toResponseBody(response.body?.contentType()))
                    .code(HttpURLConnection.HTTP_OK) // Keep original code if you want to preserve error status
                    .build()
            }
        }
        return response
    }
}

Add this interceptor to your OkHttpClient when building Retrofit:

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

val retrofit = Retrofit.Builder()
    .baseUrl("YOUR_BASE_URL")
    .client(okHttpClient)
    .addConverterFactory(GsonConverterFactory.create())
    .build()

2. 自定义Gson Converter捕获解析异常

If you want to handle exceptions directly during the parsing phase (instead of pre-validating), create a custom Converter.Factory that wraps the default Gson converter and catches JsonSyntaxException.

Example custom converter:

class SafeGsonConverterFactory(private val gson: Gson) : Converter.Factory() {
    companion object {
        fun create(gson: Gson = Gson()): SafeGsonConverterFactory {
            return SafeGsonConverterFactory(gson)
        }
    }

    override fun responseBodyConverter(
        type: Type,
        annotations: Array<out Annotation>,
        retrofit: Retrofit
    ): Converter<ResponseBody, *>? {
        val delegate = gson.getAdapter(TypeToken.get(type))
        return Converter { body ->
            try {
                delegate.fromJson(body.string())
            } catch (e: JsonSyntaxException) {
                // Return a fallback pagination model (adjust to your actual model class)
                Log.e("SafeGson", "Failed to parse JSON: ${e.message}")
                PaginationResponse(emptyList(), 1, 0)
            } finally {
                body.close()
            }
        }
    }
}

// Assume this is your pagination model class
data class PaginationResponse<T>(
    val data: List<T>,
    val page: Int,
    val total: Int
)

Use this factory instead of the default GsonConverterFactory:

val retrofit = Retrofit.Builder()
    .baseUrl("YOUR_BASE_URL")
    .client(okHttpClient)
    .addConverterFactory(SafeGsonConverterFactory.create())
    .build()

Key Notes

  • Always log invalid JSON cases during development—this helps you collaborate with the server team to fix unintended issues.
  • Choose the approach that fits your use case: interception works best for uniform handling across all pagination endpoints, while a custom converter gives you granular control per endpoint or model.

内容的提问来源于stack exchange,提问作者Maurice

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:59:34