如何使用Retrofit发送Raw格式的POST请求?
问题描述
我是Retrofit及HTTP请求的新手,目前代码结构很不稳定。成功在登录后的请求头中携带JWT字符串后,我想要发起一个POST请求。
Postman中的请求体
{"name":"PlanetX","radius":0}
我的尝试代码
//HashMap<String, Integer> body = new HashMap<String, Integer>(); //body.put("PlanetX", 0); //Planet body = new Planet("PlanetX", 0); //String text = "{\"name\":\"PlanetX\",\"radius\":0}"; //RequestBody body = RequestBody.create(MediaType.parse("text/plain"), text); JsonObject body = new JsonObject(); body.addProperty("name", "value1"); body.addProperty("id", 9); call = service.postObject(body);
POST接口定义
@POST("planets") Call<String> postObject(@Body JsonObject body); //Call<String> postObject(@Body RequestBody body); //Call<String> postObject(@Body Planet body); //Call<String> postObject(@Body HashMap<String, Integer> body);
遇到的错误
多数情况下会收到415状态码,或是如下错误:
java.lang.IllegalArgumentException: Unable to create @Body converter for class com.google.gson.JsonObject (parameter #1) for method PlanetRepository.postObject
相关实体类及RestService代码
Planet实体类
public class Planet { private long ID; private String name; private int radius; public Planet(String name, int radius ) { this.name = name; this.radius = radius; } }
RestService类
import android.content.Context; import android.widget.TextView; import android.widget.Toast; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.logging.HttpLoggingInterceptor; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.scalars.ScalarsConverterFactory; public class RestService { // Base URL private static final String BASE_URL = "http://10.0.2.2:8080/"; // BUILDER GSON private static Gson gson= new GsonBuilder() .setLenient() .create(); // BUILDER Retrofit private static Retrofit.Builder builder = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(ScalarsConverterFactory.create()); //.addConverterFactory(GsonConverterFactory.create(gson)); private static Retrofit retrofit = builder.build(); // BUILDER OkHttpClient private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); // BUILDER Logger private static HttpLoggingInterceptor logging = new HttpLoggingInterceptor() .setLevel(HttpLoggingInterceptor.Level.BASIC); // METHOD: Service Generator + Authentication public static <S> S Create(Class<S> serviceClass, final String token ) { if ( token != null ) { httpClient.interceptors().clear(); httpClient.addInterceptor( chain -> { Request original = chain.request(); Request request = original.newBuilder() //.header("Authorization", token) .header("Authorization", " Bearer "+token) .build(); return chain.proceed(request); }); httpClient.addInterceptor(logging); // Logger builder.client(httpClient.build()); retrofit = builder.build(); } return retrofit.create(serviceClass); } // METHOD: Message Generator public static void Message(Context c, TextView v, Object o) { String message; if (o instanceof Response) { message ="RESPONSE : \n" +"HEADER :\n " + ((Response<?>) o).headers() +"BODY: \n" + ((Response<?>) o).body() +"\nSTATUS: \n" + ((Response<?>) o).code(); v.setText(message); Toast.makeText(c, message, Toast.LENGTH_LONG).show(); } else if (o instanceof Throwable) { message = "Caught Throwable: \n" + o; v.setText(message); Toast.makeText(c, message, Toast.LENGTH_LONG).show(); System.out.println(message); } else if (o instanceof Exception) { message = "Caught Exception: \n" + o; v.setText(message); Toast.makeText(c, message, Toast.LENGTH_LONG).show(); System.out.println(message); } else { System.out.println("ResponseMessage does not recognizes object"); } } }
解决方案
核心问题定位
- 415状态码:服务器不支持请求的媒体类型,原因是你只配置了
ScalarsConverterFactory,缺少JSON序列化的转换器,导致请求体无法以服务器期望的application/json格式发送。 - Converter找不到错误:Retrofit没有Gson转换器,无法将
JsonObject或Planet对象转换为符合要求的请求体。
步骤1:添加Gson转换器依赖
在Module级别的build.gradle中添加依赖(版本可匹配你的Retrofit版本):
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
步骤2:启用GsonConverterFactory
修改RestService中的Retrofit构建代码,取消注释Gson转换器配置:
// BUILDER Retrofit private static Retrofit.Builder builder = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create(gson)); // 启用这一行 private static Retrofit retrofit = builder.build();
步骤3:用Planet实体类发起请求(推荐规范写法)
这是最贴合Retrofit设计的方式,能自动处理JSON序列化:
- 修正
Planet实体类字段匹配:
实体类中ID字段首字母大写,Gson默认会序列化为"ID",如果服务器不需要该字段可直接删除;若需要则添加@SerializedName保证和服务器字段名一致:public class Planet { // 服务器不需要则删除,需要则添加注解匹配字段名 @SerializedName("id") private long ID; private String name; private int radius; public Planet(String name, int radius ) { this.name = name; this.radius = radius; } } - 接口定义保留
Planet参数版本:@POST("planets") Call<String> postObject(@Body Planet body); - 发起请求的代码:
Planet body = new Planet("PlanetX", 0); call = service.postObject(body);
额外注意事项
- 自动设置Content-Type:启用Gson转换器后,Retrofit会自动添加
Content-Type: application/json请求头,解决415问题。 - JWT头格式修正:你的Authorization头写的是
" Bearer "+token,前面多了一个空格,建议改为"Bearer "+token,避免部分服务器解析失败。 - 请求体字段匹配:之前尝试的
JsonObject中添加了id字段,但Postman中的请求体没有该字段,要确保请求体字段和服务器要求完全一致。
内容的提问来源于stack exchange,提问作者Wabi-Sabi
相关产品推荐
相关产品推荐

