Retrofit2 POST请求的原始JSON数据体

5

我正在尝试使用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);

同样的错误:/
2个回答

3
错误提示说,请求体不是一个有效的 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在他的评论中提到的那样,您需要创建一个自定义POJO类来准备请求的JSON正文。或者使用HashMap来准备正文。
像下面这样创建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 body 应该包含 JSONArray,而不是 JSONObject。像下面这样

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

在API接口中将方法参数更改为List<Data>

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

我也尝试过,但还是不行。我会更新问题并添加这个解决方案的代码。 - IrApp
然后我得到了这个错误:"java.lang.IllegalStateException: 期望的是BEGIN_OBJECT,但在第1行第2列的路径$处却是BEGIN_ARRAY"。 - IrApp
1
我再次更新了我的答案。对此给您带来的不便表示抱歉。 - Shashanth

1
如果您正确使用该方法,需要传递JsonObject:
Call<TranslationResultDTO> getTranslation(@Body final JsonObject Text)

但是你传递的是类型为RequestBody的"textToTranslateBody",而不是JsonObject。你需要传递类型为JsonObject的"jsonBody"。

抱歉,这是复制/粘贴错误!我已经尝试过了,但它不起作用 :/。我的问题已更新! - IrApp
好的,明白了! - Prashanth Verma
在此处检查解决方案:https://dev59.com/YmEi5IYBdhLWcg3wUK6C - IrApp
1
你尝试过创建一个POJO类并传递吗?否则,你可以将这些值添加到Hashmap中并尝试。 - Ishan Fernando
注意:JsonObject来自于com.google.gson包,JSONObject来自于org.json包。请确保使用正确的导入语句。 - Shashanth
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接