Retrofit配置不同地址时Gson报Expected BEGIN_ARRAY but was STRING问题
Hey there, let's break down why you're seeing this Expected BEGIN_ARRAY but was STRING error with one URL but not the other—even when the returned data looks identical. Here are the most likely culprits and how to fix them:
1. 响应头 Content-Type 不一致
This is the most common reason for this issue. Even if the raw JSON data is exactly the same, your server might be sending different Content-Type headers for the two URLs:
- For
http://mysite.test/mydata.json, the server probably returnsContent-Type: application/json(standard for static JSON files). - For
http://mysite.test/?action=select, it might be returningContent-Type: text/plainor something else (common with dynamic backend scripts like PHP that echo JSON without setting the right header).
Retrofit's GsonConverterFactory is configured to only process responses marked as application/json by default. When it gets a text/plain response, it treats the entire JSON string as a single string value instead of parsing it as a JSON array—hence the error.
How to verify:
Add a logging interceptor to your OkHttpClient to inspect the response headers:
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS); OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(loggingInterceptor) .build();
Run both requests and check the Content-Type field in the logs.
Fix options:
- Server-side fix: Update your backend script to set the correct header before outputting JSON. For example, in PHP:
header('Content-Type: application/json'); echo $yourJsonData; - Client-side fix: Add a custom converter to handle
text/plainresponses with Gson:Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://mysite.test/") .client(client) .addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(new Converter.Factory() { @Override public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { // Check if we're expecting a list (adjust this to match your model type) if (type instanceof ParameterizedType && ((ParameterizedType) type).getRawType() == List.class) { return (Converter<ResponseBody, Object>) responseBody -> { String rawJson = responseBody.string(); return new Gson().fromJson(rawJson, type); }; } return super.responseBodyConverter(type, annotations, retrofit); } }) .build();
2. 响应内容包含隐形字符 (BOM 或多余空格)
Sometimes dynamic backend scripts accidentally output invisible characters before the JSON—like a UTF-8 BOM (EF BB BF), leading/trailing spaces, or newlines. Static JSON files rarely have this issue, which explains why the .json URL works.
Gson will interpret these leading characters as part of a string, causing it to fail when expecting an array.
How to verify:
Copy the raw response from both URLs into a hex editor and compare the start of the content. Look for any extra bytes before the [ that starts your array.
Fix options:
- Server-side fix: Clean up your backend output. For example, in PHP, use
ob_clean()to clear any buffered content before echoing JSON:ob_clean(); header('Content-Type: application/json'); echo $yourJsonData; - Client-side fix: Add an interceptor to strip out BOM or leading whitespace:
OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(chain -> { Response originalResponse = chain.proceed(chain.request()); ResponseBody body = originalResponse.body(); if (body != null) { String content = body.string(); // Remove UTF-8 BOM if present if (content.startsWith("\uFEFF")) { content = content.substring(1); } // Trim leading/trailing whitespace content = content.trim(); ResponseBody cleanedBody = ResponseBody.create(content, body.contentType()); return originalResponse.newBuilder().body(cleanedBody).build(); } return originalResponse; }) .build();
3. Double-check your Retrofit interface definition
While less likely, make sure your interface method is defined the same way for both URLs. For example, if you accidentally used Call<String> for the dynamic URL but Call<List<YourModel>> for the static one, that would cause this error. Double-check that both methods return the same type.
内容的提问来源于stack exchange,提问作者Danil Velter

