繁体   English   中英

Retrofit2 POST 主体作为原始 JSON

[英]Retrofit2 POST body as raw JSON

我正在尝试使用Microsoft 翻译器 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) {
            ....
        }
    });
}

我从服务器收到错误。 该错误表示 body 中的无效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);

也是同样的错误:/

错误表明正文不是有效的 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来准备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<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 响应

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

}

检测语言

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

如果你看对了方法,你需要传递 JsonObject:

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

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

这就是我的作品为当前版本的retrofit 2.6.2,

首先,我们需要将Scalars Converter添加到Gradle依赖项列表中,以将java.lang.String对象转换为text / plain请求主体,

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

然后,我们需要将转换器工厂传递给我们的改造制造商。 稍后将告诉Retrofit如何转换传递给服务的@Body参数。

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

注意:在我的改造生成器中,我有两个转换器GsonScalars您可以将它们都用于发送我们需要关注的Json主体,因此,如果您不需要Gson删除它

然后使用String主体参数进行翻新服务。

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

然后创建json主体

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

致电您的服务

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

暂无
暂无

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

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