这个问题以前可能被问过,但没有明确的答案。如何在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中这样做吗?


当前回答

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。

其他回答

经过如此多的努力,发现基本的区别是您需要发送JsonObject而不是JsonObject作为参数。

我想比较排射的速度和改装的发送和接收数据,我写在下面的代码(改装部分)

第一个依赖:

dependencies {
     implementation 'com.squareup.retrofit2:retrofit:2.4.0'
     implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
}

然后界面:

 public interface IHttpRequest {

    String BaseUrl="https://example.com/api/";

    @POST("NewContract")
    Call<JsonElement> register(@Body HashMap registerApiPayload);
}

和一个函数来设置参数,张贴数据到服务器(在MainActivity):

private void Retrofit(){

    Retrofit retrofitRequest = new Retrofit.Builder()
            .baseUrl(IHttpRequest.BaseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    // set data to send
    HashMap<String,String> SendData =new HashMap<>();
    SendData.put("token","XYXIUNJHJHJHGJHGJHGRTYTRY");
    SendData.put("contract_type","0");
    SendData.put("StopLess","37000");
    SendData.put("StopProfit","48000");

    final IHttpRequest request=retrofitRequest.create(IHttpRequest.class);

    request.register(SendData).enqueue(new Callback<JsonElement>() {
        @Override
        public void onResponse(Call<JsonElement> call, Response<JsonElement> response) {
            if (response.isSuccessful()){
                Toast.makeText(getApplicationContext(),response.body().toString(),Toast.LENGTH_LONG).show();
            }
        }

        @Override
        public void onFailure(Call<JsonElement> call, Throwable t) {

        }
    });

}

对我来说,改装比截击更快。

添加ScalarsConverterFactory.create()方法并传递硬代码

如果不想为每个API调用都创建pojo类,可以使用hashmap。

HashMap<String,String> hashMap=new HashMap<>();
        hashMap.put("email","this@gmail.com");
        hashMap.put("password","1234");

然后像这样发送

Call<JsonElement> register(@Body HashMap registerApiPayload);

为了更清楚地说明这里给出的答案,下面是如何使用扩展函数。这仅适用于使用Kotlin的情况

如果你正在使用com.squareup.okhttp3:okhttp:4.0.1,旧的创建MediaType和RequestBody对象的方法已经被弃用,不能在Kotlin中使用。

如果您希望使用扩展函数从字符串中获取MediaType对象和ResponseBody对象,首先将以下行添加到您希望在其中使用它们的类中。

import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody

现在可以通过这种方式直接获取MediaType对象

val mediaType = "application/json; charset=utf-8".toMediaType()

要获得RequestBody的对象,首先要将您想要发送的JSONObject转换为字符串。您必须将mediaType对象传递给它。

val requestBody = myJSONObject.toString().toRequestBody(mediaType)