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

Retrofit配置不同地址时Gson报Expected BEGIN_ARRAY but was STRING问题

问题分析:Retrofit + Gson 解析相同数据却报错的原因

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 returns Content-Type: application/json (standard for static JSON files).
  • For http://mysite.test/?action=select, it might be returning Content-Type: text/plain or 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/plain responses 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 09:07:24