【问题标题】:Retrofit2 POST body as raw JSONRetrofit2 POST 正文作为原始 JSON
【发布时间】:2018-09-05 08:40:26
【问题描述】:

我正在尝试使用Microsoft translator API 翻译一些文本。我正在使用Retrofit 2。这是代码:

 public RestClient() {
    final OkHttpClient httpClient = new OkHttpClient.Builder()
            .addNetworkInterceptor(new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    final Request originalRequest = chain.request();
                    Request newRequest;

                    newRequest = originalRequest.newBuilder()
                            .header("Content-Type", "application/json")
                            .header("Ocp-Apim-Subscription-Key", "KEY")
                            .header("X-ClientTraceId", java.util.UUID.randomUUID().toString())
                            .build();
                    return chain.proceed(newRequest);
                }
            })
            .addNetworkInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
            .build();


    // Build the retrofit config from our http client
    final Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://api.cognitive.microsofttranslator.com/")
            .client(httpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    // Build api instance from retrofit config
    api = retrofit.create(RestApi.class);
}


public interface RestApi {

    @POST("translate?api-version=3.0&from=en&to=zh-Latn")
    Call<TranslationResultDTO> getTranslation(@Body final RequestBody Text);
}


 public void getTranslation(final String text, final RestCallback<TranslationResultDTO> translationResultCallback) {
    final JsonObject jsonBody = new JsonObject();
    jsonBody.addProperty("Text", text);
    RequestBody textToTranslateBody = RequestBody.create(MediaType.parse("application/json"), jsonBody.toString());

    Call<TranslationResultDTO> call = api.getTranslation(textToTranslateBody);

    call.enqueue(new Callback<TranslationResultDTO>() {
        @Override
        public void onResponse(Call<TranslationResultDTO> call, retrofit2.Response<TranslationResultDTO> response) {
            final int responseCode = response.code();
            ....
        }

        @Override
        public void onFailure(Call<TranslationResultDTO> call, Throwable t) {
            ....
        }
    });
}

我从服务器收到一个错误。该错误表明正文不是有效的JSON

有人知道问题出在哪里吗? 提前致谢!

更新

这是我也尝试过的另一个解决方案的代码。此解决方案使用 POJO 类:

public class Data {

@SerializedName("Text")
private String text;

public Data(String text) {
    this.text = text;
}

public String getText() {
    return text;
}

public void setText(String text) {
    this.text = text;
}

}

@POST("translate?api-version=3.0&from=en&to=zh-Latn")
Call<TranslationResultDTO> getTranslation(@Body final Data Text);


 Data data = new Data("text value to translate");
    Call<TranslationResultDTO> call = api.getTranslation(data);

同样的错误:/

【问题讨论】:

    标签: android post request retrofit2


    【解决方案1】:

    错误表明正文不是有效的 JSON。

    这是来自服务器的预期响应。假设下面是您要发送的 JSON 正文,

    {
        "key_1" : "value 1",
        "key_2" : "value 2",
    }
    

    当你使用JsonObject#toString()时,它会变成这样

    {\"key_1\" : \"value 1\", \"key_2\" : \"value 2\"}
    

    如果您将上述 JSON 数据/正文发送到服务器,服务器会将其视为普通字符串。

    您仍然需要在这里使用toString(),因为MediaType#parse() 不接受JsonObject 参数。

    解决办法是什么?

    正如 Ishan Fernando 在他的 comment 中提到的,您需要创建一个自定义 POJO 类来为请求准备 JSON 正文。或者使用HashMap来准备body。

    如下创建 POJO

    import com.google.gson.annotations.SerializedName;
    
    public class Data {
    
        @SerializedName("Text")
        private String text;
    
        public Data(String text) {
            this.text = text;
        }
    
        // getter and setter methods
    }
    

    并使用它

    Data data = new Data("text value to translate"); // construct object
    Call<TranslationResultDTO> call = api.getTranslation(data); // change method parameter
    

    还有调整API接口中的方法参数

    Call<TranslationResultDTO> getTranslation(@Body final Data text); // change method parameter
    

    编辑 1

    我浏览了您问题所附的文档。我犯了一个小错误。 JSON 正文应包含 JSONArray,而不是 JSONObject。如下所示

    [
        {
            "Text" : "text to translate"
        }
    ]
    

    API接口中方法参数改为List&lt;Data&gt;

    Call<TranslationResultDTO> getTranslation(@Body final List<Data> text); // change method parameter
    

    像下面这样使用它

    Data data = new Data("text value to translate"); // construct object
    List<Data> objList = new ArrayList<>();
    objList.add(data);
    Call<TranslationResultDTO> call = api.getTranslation(objList);  // change method parameter
    

    编辑 2

    API 也会响应 JSONArray。示例响应

    [
        {
            "detectedLanguage": {
            "language": "en",
            "score": 1.0
            },
            "translations": [
            {
                "text": "Hallo Welt!",
                "to": "de"
            },
            {
                "text": "Salve, mondo!",
                "to": "it"
                }
            ]
        }
    ]
    

    在下面创建 POJO 类以正确解析 JSON 响应

    Translation.java

    import com.google.gson.annotations.Expose;
    import com.google.gson.annotations.SerializedName;
    
    public class Translation {
    
        @SerializedName("text")
        @Expose
        private String text;
        @SerializedName("to")
        @Expose
        private String to;
    
        // constructors, getter and setter methods
    
    }
    

    DetectedLanguage.java

    import com.google.gson.annotations.Expose;
    import com.google.gson.annotations.SerializedName;
    
    public class DetectedLanguage {
    
        @SerializedName("language")
        @Expose
        private String language;
        @SerializedName("score")
        @Expose
        private float score;
    
        // constructors, getter and setter methods
    
    }
    

    最后,调整 TranslationResultDTO.java 类,如下所示。

    import java.util.List;
    import com.google.gson.annotations.Expose;
    import com.google.gson.annotations.SerializedName;
    
    public class TranslationResultDTO {
    
        @SerializedName("detectedLanguage")
        @Expose
        private DetectedLanguage detectedLanguage;
        @SerializedName("translations")
        @Expose
        private List<Translation> translations = null;
    
        // constructors, getter and setter methods
    
    }
    

    接口类

    Call<List<TranslationResultDTO>> call = api.getTranslation(objList);    // change method parameter
    

    【讨论】:

    • 我也试过了,也没用。我将更新问题以添加此解决方案的代码
    • 然后我得到这个错误:“java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $”
    • 我再次更新了我的答案。很抱歉给您带来不便
    【解决方案2】:

    如果你看到方法正确,你需要传递JsonObject:

    Call<TranslationResultDTO> getTranslation(@Body final JsonObject Text)
    

    但是,您传递的是 RequestBody 类型的“textToTranslateBody”,而不是 JsonObject。您必须传递 JsonObject 类型的“jsonBody”。

    【讨论】:

    • 对不起,这是一个复制/粘贴错误!我已经尝试过了,但它不起作用:/。我的问题更新了!
    • 好的..明白了..!!
    • 我没有得到一件事,你为什么不发送JsonObject,你为什么要发送“RequestBody”类型? “RequestBody”是 POJO 吗?如果是 POJO 则将 POJO 转换为 JsonObject 并传递 JsonObject
    • RequestBody 是来自okhttp3 的一个类。我也尝试过使用 JsonObject,但它们的展位不工作
    • 您是否尝试创建一个 POJO 类并通过它?否则,您可以将这些值添加到 Hashmap 并尝试。
    猜你喜欢
    • 1970-01-01
    • 2015-12-02
    • 2016-05-23
    • 1970-01-01
    • 2017-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-02
    相关资源
    最近更新 更多