如何在一个Retrofit请求的正文中发布原始的整个JSON?

这个问题以前可能有人问过,但是没有得到明确的答复。 如何在改造请求的正文中发布原始整个JSON?

在这里看到类似的问题 或者是这个答案正确的,它必须是formsURL编码,并作为一个字段传递 ? 我真的希望不要,因为我连接的服务只是期望在post正文中的原始JSON。 他们没有设置为查找JSON数据的特定字段。

我只想和其他人一起澄清这个问题。 一个人回答不要使用Retrofit。 另一个不是确定的语法。 另一个认为是可以做的,但只有当它的formsurl编码和放置在一个领域(这是不能接受的在我的情况)。 不,我无法重新编码我的Android客户端的所有服务。 是的,在主要的项目中发布原始JSON而不是传递JSON内容作为字段属性值是非常常见的。 让我们把它正确的,继续前进。 有人可以指向显示如何完成的文档或示例吗? 或者提供一个可以/不应该做的正当理由。

更新:有一件事我可以100%确定地说。 你可以在Google的排球中做到这一点。 它是build立在英寸我们可以做到这一点在改造?

@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被定义为“具有关联的MIMEtypes的二进制数据”。 使用上面的声明,有两种方法可以轻松发送原始数据:

  1. 使用TypedByteArray发送原始字节和JSON MIMEtypes:

     String json = "{\"foo\":\"kit\",\"bar\":\"kat\"}"; TypedInput in = new TypedByteArray("application/json", json.getBytes("UTF-8")); FooResponse response = foo.postRawJson(in); 
  2. 子类TypedString创build一个TypedJsonString类:

     public class TypedJsonString extends TypedString { public TypedJsonString(String body) { super(body); } @Override public String mimeType() { return "application/json"; } } 

    然后使用类似于#1的类的实例。

例如,我们也可以直接使用HashMap<String, Object>发送主体参数,而不是类

 interface Foo { @POST("/jayson") FooResponse postJson(@Body HashMap<String, Object> body); } 

是的,我知道这是迟到了,但有人可能会从中受益。

使用Retrofit2:

昨天晚上我遇到了这个问题,从Volley迁移到Retrofit2(和OP一样,这是用JsonObjectRequest构build到Volley中的),虽然Jake的回答对于Retrofit1.9来说是正确的 ,但是Retrofit2没有TypedString

我的情况需要发送一个Map<String,Object> ,它可以包含一些空值,转换成一个JSONObject(不会用@FieldMap飞,也不@FieldMap特殊的字符,有些会被转换),所以下面的@bnorms提示和方形表示:

可以指定一个对象作为带有@Body注解的HTTP请求体。

该对象也将使用Retrofit实例上指定的转换器进行转换。 如果没有添加转换器,则只能使用RequestBody。

所以这是一个使用RequestBodyResponseBody的选项:

在你的界面中使用带有RequestBody @Body

 public interface ServiceApi { @POST("prefix/user/{login}") Call<ResponseBody> login(@Path("login") String postfix, @Body RequestBody params); } 

在您的调用点创build一个RequestBody ,指出它是MediaType,并使用JSONObject将您的地图转换为适当的格式:

 Map<String, Object> map = new ArrayMap<>(); //put something inside the map, could be null jsonParams.put("code", some_code); RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"),(new JSONObject(jsonParams)).toString()); //serviceCaller is the interface initialized with retrofit.create... Call<ResponseBody> response = serviceCaller.login("loginpostfix", body); response.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> rawResponse) { try { //get your response.... Log.d(TAG, "RetroFit2.0 :RetroGetLogin: " + rawResponse.body().string()); } catch (Exception e) { e.printStackTrace(); } } @Override public void onFailure(Call<ResponseBody> call, Throwable throwable) { // other stuff... } }); 

希望这有助于任何人!

使用JsonObject是这样的:

  1. 像这样创build你的界面:

      public interface laInterfaz{ @POST("/bleh/blah/org") void registerPayer(@Body JsonObject bean, Callback<JsonObject> callback); } 
  2. 根据jsons结构创buildJsonObject。

     JsonObject obj = new JsonObject(); JsonObject payerReg = new JsonObject(); payerReg.addProperty("crc","aas22"); payerReg.addProperty("payerDevManufacturer","Samsung"); obj.add("payerReg",payerReg); /*json/* {"payerReg":{"crc":"aas22","payerDevManufacturer":"Samsung"}} /*json*/ 
  3. 致电服务:

      service.registerPayer(obj, callBackRegistraPagador); Callback<JsonObject> callBackRegistraPagador = new Callback<JsonObject>(){ public void success(JsonObject object, Response response){ System.out.println(object.toString()); } public void failure(RetrofitError retrofitError){ System.out.println(retrofitError.toString()); } 

    };

而且它! 以我个人的观点来看,它要比制作pojos和解决课堂上的混乱要好得多。 这是更清洁。

Retrofit2中 ,当你想以原始的方式发送你的参数时,你必须使用Scalars

首先在你的gradle中添加这个:

 compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:converter-gson:2.3.0' compile 'com.squareup.retrofit2:converter-scalars:2.3.0' 

你的界面

 public interface ApiInterface { String URL_BASE = "http://10.157.102.22/rest/"; @Headers("Content-Type: application/json") @POST("login") Call<User> getUser(@Body String body); } 

活动

  public class SampleActivity extends AppCompatActivity implements Callback<User> { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sample); Retrofit retrofit = new Retrofit.Builder() .baseUrl(ApiInterface.URL_BASE) .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .build(); ApiInterface apiInterface = retrofit.create(ApiInterface.class); // prepare call in Retrofit 2.0 try { JSONObject paramObject = new JSONObject(); paramObject.put("email", "sample@gmail.com"); paramObject.put("pass", "4384984938943"); Call<User> userCall = apiInterface.getUser(paramObject.toString()); userCall.enqueue(this); } catch (JSONException e) { e.printStackTrace(); } } @Override public void onResponse(Call<User> call, Response<User> response) { } @Override public void onFailure(Call<User> call, Throwable t) { } } 

我特别喜欢Jake 上面提到的TypedString子类。 你确实可以根据你计划推出的POST数据的种类来创build各种子类,每个子类都有自己的一组一致的调整。

您也可以select在您的Retrofit API中为您的JSON POST方法添加标头注释…

 @Headers( "Content-Type: application/json" ) @POST("/json/foo/bar/") Response fubar( @Body TypedString sJsonBody ) ; 

…但使用子类更明显是自我logging。

 @POST("/json/foo/bar") Response fubar( @Body TypedJsonString jsonBody ) ;