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


当前回答

添加ScalarsConverterFactory进行改造:

在gradle:

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

你的改造:

retrofit = new Retrofit.Builder()
            .baseUrl(WEB_DOMAIN_MAIN)
            .addConverterFactory(ScalarsConverterFactory.create())
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build();

改变你的调用接口@Body参数为String,不要忘记添加@Headers("Content-Type: application/json"):

@Headers("Content-Type: application/json")
@POST("/api/getUsers")
Call<List<Users>> getUsers(@Body String rawJsonString);

现在你可以发布raw json了。

其他回答

@Body注释定义了一个请求主体。

interface Foo {
  @POST("/jayson")
  FooResponse postJson(@Body FooRequest body);
}

由于Retrofit默认使用Gson,因此FooRequest实例将被序列化为JSON作为请求的唯一主体。

public class FooRequest {
  final String foo;
  final String bar;

  FooRequest(String foo, String bar) {
    this.foo = foo;
    this.bar = bar;
  }
}

调用:

FooResponse = foo.postJson(new FooRequest("kit", "kat"));

将产生以下主体:

{"foo":"kit","bar":"kat"}

Gson文档中有更多关于对象序列化如何工作的内容。

现在,如果你真的非常想自己发送“原始”JSON作为正文(但请使用Gson !),你仍然可以使用TypedInput:

interface Foo {
  @POST("/jayson")
  FooResponse postRawJson(@Body TypedInput body);
}

TypedInput被定义为“具有关联mime类型的二进制数据”。有两种方法可以使用上述声明轻松发送原始数据:

Use TypedByteArray to send raw bytes and the JSON mime type: String json = "{\"foo\":\"kit\",\"bar\":\"kat\"}"; TypedInput in = new TypedByteArray("application/json", json.getBytes("UTF-8")); FooResponse response = foo.postRawJson(in); Subclass TypedString to create a TypedJsonString class: public class TypedJsonString extends TypedString { public TypedJsonString(String body) { super(body); } @Override public String mimeType() { return "application/json"; } } And then use an instance of that class similar to #1.

在创建OkHttpClient时,将用于Retrofit。

像这样增加一个拦截器。

 private val httpClient = OkHttpClient.Builder()
        .addInterceptor (other interceptors)
        ........................................

        //This Interceptor is the main logging Interceptor
        .addInterceptor { chain ->
            val request = chain.request()
            val jsonObj = JSONObject(Gson().toJson(request))

            val requestBody = (jsonObj
            ?.getJSONObject("tags")
            ?.getJSONObject("class retrofit2.Invocation")
            ?.getJSONArray("arguments")?.get(0) ?: "").toString()
            val url = jsonObj?.getJSONObject("url")?.getString("url") ?: ""
            
            Timber.d("gsonrequest request url: $url")
            Timber.d("gsonrequest body :$requestBody")

            chain.proceed(request)
        }
        
        ..............
        // Add other configurations
        .build()

现在,您的每个Retrofit调用的URL和请求正文将被记录在Logcat中。用"gsonrequest"过滤

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

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

你需要在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);

这对我来说很管用:

火通话

@Headers("Content-Type: application/json")
@POST("/set_data")
Call<CommonResponse> setPreferences(@Body RequestData request);

注意:使用Retrofit的GSON库

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class RequestData {

    @SerializedName("access_token")
    @Expose
    private String accessToken;

    @SerializedName("data")
    @Expose
    private Data data;
    // The above 'Data' is another similar class to add inner JSON objects. JSONObject within a JSONObject.

    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }

    public void setData(Data data) {
        this.data = data;
    }
}

我想这将有所帮助,您可能已经拥有了所有集成,我们不需要任何花哨的东西来使用上面的代码片段。它非常适合我。