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

