简体   繁体   English

Retrofit2 POST 主体作为原始 JSON

[英]Retrofit2 POST body as raw JSON

I am trying to translate some text by using Microsoft translator API .我正在尝试使用Microsoft 翻译器 API翻译一些文本。 I am using Retrofit 2 .我正在使用Retrofit 2 This is the code:这是代码:

 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) {
            ....
        }
    });
}

I get an error from the server.我从服务器收到错误。 The error says that the body in not a valid JSON .该错误表示 body 中的无效JSON

Does someone know where is the problem??有人知道问题出在哪里吗?? Thanks in advance!提前致谢!

UPDATE更新

Here is the code for another solution I have tried as well.这是我也尝试过的另一个解决方案的代码。 This solution is using a POJO class:此解决方案使用 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);

Also the same error :/也是同样的错误:/

The error says that the body in not a valid JSON.错误表明正文不是有效的 JSON。

It was an expected response from server.这是来自服务器的预期响应。 Let's say below is your JSON body that you want to send,假设下面是您要发送的 JSON 正文,

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

When you use JsonObject#toString() , it'll become like this当你使用JsonObject#toString() ,它会变成这样

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

If you send above JSON data/body to the server, it'll be treated as normal String by the server.如果您将上述 JSON 数据/正文发送到服务器,服务器会将其视为普通字符串。

Still you need to use toString() here because MediaType#parse() doesn't accept JsonObject parameters.你仍然需要在这里使用toString()因为MediaType#parse()不接受JsonObject参数。

What's the solution?解决办法是什么?

As Ishan Fernando mentioned in his comment you need to create a custom POJO class to prepare the JSON body for the request.正如 Ishan Fernando 在他的评论中提到的,您需要创建一个自定义 POJO 类来为请求准备 JSON 正文。 Or use HashMap to prepare the body.或者使用HashMap来准备body。

Create POJO like below创建如下 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
}

And use it并使用它

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

And also adjust the method parameter in API interface并且还调整了API接口中的方法参数

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

Edit 1编辑 1

I went through the documentation attached to your question.我浏览了您的问题所附的文档。 I made a little mistake.我犯了一个小错误。 JSON body should contain JSONArray, not JSONObject. JSON 正文应包含 JSONArray,而不是 JSONObject。 Like below像下面

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

Change method parameter to List<Data> in the API interface在 API 接口中将方法参数更改为List<Data>

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

Use it like below像下面一样使用它

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

Edit 2编辑 2

And also API will respond with JSONArray.而且 API 也会用 JSONArray 响应。 Sample response样本响应

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

Create below POJO classes to parse JSON response properly创建以下 POJO 类以正确解析 JSON 响应

Translation.java翻译.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

}

And finally, adjust TranslationResultDTO.java class like below.最后,调整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

}

Interface class接口类

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

If you see the method right, u need to pass JsonObject:如果你看对了方法,你需要传递 JsonObject:

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

But instead you are passing "textToTranslateBody" which is of type RequestBody not JsonObject.但相反,您传递的是 RequestBody 类型而不是 JsonObject 类型的“textToTranslateBody”。 You have to pass "jsonBody" which is of type JsonObject.您必须传递 JsonObject 类型的“jsonBody”。

This is what works me for the current version of retrofit 2.6.2 , 这就是我的作品为当前版本的retrofit 2.6.2,

First of all, we need to add a Scalars Converter to the list of our Gradle dependencies, which would take care of converting java.lang.String objects to text/plain request bodies, 首先,我们需要将Scalars Converter添加到Gradle依赖项列表中,以将java.lang.String对象转换为text / plain请求主体,

implementation'com.squareup.retrofit2:converter-scalars:2.6.2'

Then, we need to pass a converter factory to our Retrofit builder. 然后,我们需要将转换器工厂传递给我们的改造制造商。 It will later tell Retrofit how to convert the @Body parameter passed to the service. 稍后将告诉Retrofit如何转换传递给服务的@Body参数。

private val retrofitBuilder: Retrofit.Builder by lazy {
    Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(ScalarsConverterFactory.create())
        .addConverterFactory(GsonConverterFactory.create())
}

Note: In my retrofit builder i have two converters Gson and Scalars you can use both of them put to send Json body we need to focus so if you don't need Gson remove it 注意:在我的改造生成器中,我有两个转换器GsonScalars您可以将它们都用于发送我们需要关注的Json主体,因此,如果您不需要Gson删除它

Then Retrofit service with a String body parameter. 然后使用String主体参数进行翻新服务。

@Headers("Content-Type: application/json")
@POST("users")
fun saveUser(@Body   user: String): Response<MyResponse>

Then create the json body 然后创建json主体

val user = JsonObject()
 user.addProperty("id", 001)
 user.addProperty("name", "Name")

Call your service 致电您的服务

RetrofitService.myApi.saveUser(user.toString())

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM