这个问题以前可能被问过,但没有明确的答案。如何在Retrofit请求的主体中发布原始的整个JSON ?

在这里看到类似的问题。或者这个答案是正确的,它必须是表单url编码并作为一个字段传递?我真的希望不是,因为我要连接的服务只是希望在文章正文中有原始JSON。它们不是用来为JSON数据寻找特定字段的。

I just want to clarify this with the restperts once and for all. One person answered not to use Retrofit. The other was not certain of the syntax. Another thinks yes it can be done but only if its form url-encoded and placed in a field (that's not acceptable in my case). No, I can't re-code all the services for my Android client. And yes, it's very common in major projects to post raw JSON instead of passing over JSON content as field property values. Let's get it right and move on. Can someone point to the documentation or example that shows how this is done? Or provide a valid reason why it can/should not be done.

更新:有一件事我可以百分之百确定。你可以在谷歌的Volley中做到这一点。这是与生俱来的。我们可以在Retrofit中这样做吗?


当前回答

我试了一下: 当你创建你的Retrofit实例时,将这个转换器工厂添加到Retrofit构建器中:

gsonBuilder = new GsonBuilder().serializeNulls()     
your_retrofit_instance = Retrofit.Builder().addConverterFactory( GsonConverterFactory.create( gsonBuilder.create() ) )

其他回答

解决了我的问题基于TommySM的答案(见前)。 但是我不需要登录,我使用Retrofit2来测试https GraphQL API,就像这样:

Defined my BaseResponse class with the help of json annotations (import jackson.annotation.JsonProperty). public class MyRequest { @JsonProperty("query") private String query; @JsonProperty("operationName") private String operationName; @JsonProperty("variables") private String variables; public void setQuery(String query) { this.query = query; } public void setOperationName(String operationName) { this.operationName = operationName; } public void setVariables(String variables) { this.variables = variables; } } Defined the call procedure in the interface: @POST("/api/apiname") Call<BaseResponse> apicall(@Body RequestBody params); Called apicall in the body of test: Create a variable of MyRequest type (for example "myLittleRequest"). Map<String, Object> jsonParams = convertObjectToMap(myLittleRequest); RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), (new JSONObject(jsonParams)).toString()); response = hereIsYourInterfaceName().apicall(body).execute();

这是我在当前版本的2.6.2中工作的地方,

首先,我们需要添加一个Scalars Converter到我们的Gradle依赖项列表中,它负责将java.lang.String对象转换为文本/纯请求体,

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

然后,我们需要将一个转换器工厂传递给我们的Retrofit构建器。它稍后将告诉Retrofit如何转换传递给服务的@Body参数。

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

注:在我的改造建设者我有两个转换器Gson和 标量,你可以使用他们,但发送Json的主体,我们需要 focus Scalars,所以如果你不需要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())

1)——添加依赖关系

 compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'

2)创建Api Handler类

    public class ApiHandler {


  public static final String BASE_URL = "URL";  

    private static Webservices apiService;

    public static Webservices getApiService() {

        if (apiService == null) {

           Gson gson = new GsonBuilder()
                    .setLenient()
                    .create();
            Retrofit retrofit = new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(gson)).baseUrl(BASE_URL).build();

            apiService = retrofit.create(Webservices.class);
            return apiService;
        } else {
            return apiService;
        }
    }


}

3)从Json模式2 pojo制作bean类

还记得 -目标语言:Java -源类型:JSON 注释风格:Gson -select包含getter和setter -你也可以选择允许附加属性

http://www.jsonschema2pojo.org/

4)建立API调用接口

    public interface Webservices {

@POST("ApiUrlpath")
    Call<ResponseBean> ApiName(@Body JsonObject jsonBody);

}

如果你有一个表单数据参数,那么在下面添加

@Headers("Content-Type: application/x-www-form-urlencoded")

其他方式的表单数据参数检查此链接

5)make JsonObject作为参数传递给body

 private JsonObject ApiJsonMap() {

    JsonObject gsonObject = new JsonObject();
    try {
        JSONObject jsonObj_ = new JSONObject();
        jsonObj_.put("key", "value");
        jsonObj_.put("key", "value");
        jsonObj_.put("key", "value");


        JsonParser jsonParser = new JsonParser();
        gsonObject = (JsonObject) jsonParser.parse(jsonObj_.toString());

        //print parameter
        Log.e("MY gson.JSON:  ", "AS PARAMETER  " + gsonObject);

    } catch (JSONException e) {
        e.printStackTrace();
    }

    return gsonObject;
}

6)像这样调用Api

private void ApiCallMethod() {
    try {
        if (CommonUtils.isConnectingToInternet(MyActivity.this)) {
            final ProgressDialog dialog;
            dialog = new ProgressDialog(MyActivity.this);
            dialog.setMessage("Loading...");
            dialog.setCanceledOnTouchOutside(false);
            dialog.show();

            Call<ResponseBean> registerCall = ApiHandler.getApiService().ApiName(ApiJsonMap());
            registerCall.enqueue(new retrofit2.Callback<ResponseBean>() {
                @Override
                public void onResponse(Call<ResponseBean> registerCall, retrofit2.Response<ResponseBean> response) {

                    try {
                        //print respone
                        Log.e(" Full json gson => ", new Gson().toJson(response));
                        JSONObject jsonObj = new JSONObject(new Gson().toJson(response).toString());
                        Log.e(" responce => ", jsonObj.getJSONObject("body").toString());

                        if (response.isSuccessful()) {

                            dialog.dismiss();
                            int success = response.body().getSuccess();
                            if (success == 1) {



                            } else if (success == 0) {



                            }  
                        } else {
                            dialog.dismiss();


                        }


                    } catch (Exception e) {
                        e.printStackTrace();
                        try {
                            Log.e("Tag", "error=" + e.toString());

                            dialog.dismiss();
                        } catch (Resources.NotFoundException e1) {
                            e1.printStackTrace();
                        }

                    }
                }

                @Override
                public void onFailure(Call<ResponseBean> call, Throwable t) {
                    try {
                        Log.e("Tag", "error" + t.toString());

                        dialog.dismiss();
                    } catch (Resources.NotFoundException e) {
                        e.printStackTrace();
                    }
                }

            });

        } else {
            Log.e("Tag", "error= Alert no internet");


        }
    } catch (Resources.NotFoundException e) {
        e.printStackTrace();
    }
}

你需要在interface中设置@Body

@Headers({ "Content-Type: application/json;charset=UTF-8"})
    @POST("Auth/Login")
    Call<ApiResponse> loginWithPhone(@Body HashMap<String, String> fields);

要通过生身改装就用:

 HashMap<String,String> SendData =new HashMap<>();
        SendData.put("countryCode",ccode);
        SendData.put("phoneNumber",phone);

        Call<ApiResponse>call = serviceInterface.loginWithPhone(SendData);

这对我来说很管用:

2022年的最新解决方案:

首先要检查的一件事是,您的post请求是否通过第三方API(如postman)工作。在遇到本页上的解决方案之前,我已经这样做了。

下一步是向您的改装实例添加日志记录功能。点击这里了解如何添加日志记录来进行改造。

在添加日志记录时,我看到了一个500服务器错误,基于端点通过Postman工作的事实,我们知道错误一定与传递给Post方法的数据格式有关。

你的改造建设者应该是这样的:

val retrofitInstance = Retrofit.Builder()
            .baseUrl("https://pacific-tundra-61285.herokuapp.com/")
            .addConverterFactory(ScalarsConverterFactory.create())
            .addConverterFactory(GsonConverterFactory.create())
            .client(httpClient)
            .build()

这篇文章帮助解决了这个问题,并提供了在发出post请求时将对象转换为正确的“application/json”格式的正确方法。在kotlin版本中使用了一些废弃的方法,新代码非常相似:

private fun createRequestBody(vararg params : Pair<String, Any>) =
        JSONObject(mapOf(*params)).toString()
            .toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())

pair中的泛型值参数被设置为Any,以便您可以处理与对象相关的不同类型。

为了清晰起见,最后一部分是实际的post方法和用于调用post请求的代码。

@POST("create/")
    fun create(@Body params : RequestBody) : Call<YourObject>
val call = apiService.create(createRequestBody( 
"string" to object // You should pass in any key and value pairs here.

最后像往常一样调用enqueue。