如何在一个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的二进制数据”。 使用上面的声明,有两种方法可以轻松发送原始数据:
-
使用TypedByteArray发送原始字节和JSON MIMEtypes:
String json = "{\"foo\":\"kit\",\"bar\":\"kat\"}"; TypedInput in = new TypedByteArray("application/json", json.getBytes("UTF-8")); FooResponse response = foo.postRawJson(in);
-
子类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。
所以这是一个使用RequestBody
和ResponseBody
的选项:
在你的界面中使用带有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是这样的:
-
像这样创build你的界面:
public interface laInterfaz{ @POST("/bleh/blah/org") void registerPayer(@Body JsonObject bean, Callback<JsonObject> callback); }
-
根据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*/
-
致电服务:
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 ) ;