使用Retrofit2发送POST请求时遭遇403状态码问题
问题描述
使用Retrofit2向服务器提交JSON数据时始终返回403状态码,但相同请求在Postman中可以正常执行。已尝试添加Postman自动生成的所有请求头,问题仍未解决。相关代码如下:
ApiInterface代码
public interface ApiInterface { String BASE_URL = "https:example.com"; @Headers({"Content-Type: application/json", "User-Agent: PostmanRuntime/7.29.2", "Accept: */*", "Cache-Control: no-cache", "Postman-Token: 9151e8a4-7665 - 416d - b2f5 - a84f0736a7ba", "Host: xyz.com", "Accept-Encoding:gzip, deflate, br", "Content-Length: 76" }) @POST("add_aadharinfo") Call<DataClass> posImages(@Body JSONObject data); }
MainActivity中的Retrofit代码
private void ImageInfo() throws JSONException { Retrofit retrofit = new Retrofit.Builder() .baseUrl(ApiInterface.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); ApiInterface apiInterface = retrofit.create(ApiInterface.class); JSONObject dataInfo = new JSONObject(); dataInfo.put("phone",contact); dataInfo.put("profile_image",encoded); dataInfo.put("aadhar_image",encoded22); Call<DataClass> usercall = apiInterface.posImages(dataInfo); usercall.enqueue(new Callback<DataClass>() { @Override public void onResponse(Call<DataClass> call, retrofit2.Response<DataClass> response) { if (response.isSuccessful()) { Toast.makeText(SignUpActivity.this,response.body().getMessage(),Toast.LENGTH_LONG).show(); } Log.d("response", "onResponse: "+response.code()); } @Override public void onFailure(Call<DataClass> call, Throwable t) { Toast.makeText(SignUpActivity.this,"fail"+t.getLocalizedMessage(),Toast.LENGTH_LONG).show(); } }); }
DataClass代码
public class DataClass { private String message; private String data; public DataClass(String message, String data) { this.message = message; this.data = data; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getData() { return data; } public void setData(String data) { this.data = data; } }
解决方案
1. 删除硬编码的Content-Length请求头
你在@Headers中固定了Content-Length: 76,但实际请求的JSON数据长度必然和该值不符,服务器会判定请求篡改并返回403。直接移除这个请求头,Retrofit会自动计算并设置正确的长度。
2. 用实体类替代JSONObject作为请求体
Retrofit配合GsonConverterFactory时,使用实体类作为@Body参数能避免JSON序列化的格式问题:
- 创建请求实体类:
public class AadharRequest { private String phone; private String profile_image; private String aadhar_image; public AadharRequest(String phone, String profile_image, String aadhar_image) { this.phone = phone; this.profile_image = profile_image; this.aadhar_image = aadhar_image; } // 生成getter和setter方法 }
- 修改ApiInterface方法:
@POST("add_aadharinfo") Call<DataClass> posImages(@Body AadharRequest data);
- 替换ImageInfo方法中的JSONObject:
AadharRequest request = new AadharRequest(contact, encoded, encoded22); Call<DataClass> usercall = apiInterface.posImages(request);
3. 统一BASE_URL与Host头
你的BASE_URL是https:example.com,但Host头为xyz.com,二者必须一致。修正BASE_URL为https://xyz.com/(补全协议和末尾斜杠),或者直接移除Host头,让Retrofit自动处理。
4. 移除Postman专属请求头
Postman-Token是Postman的临时标识,服务器可能会验证该值,而你使用固定值会导致验证失败。直接删除这个请求头。
5. 添加日志拦截器排查请求差异
使用OkHttp日志拦截器对比Retrofit请求与Postman请求的细节(包括请求头、请求体),找出差异:
- 依赖添加:
implementation 'com.squareup.okhttp3:logging-interceptor:4.11.0'
- 修改Retrofit构建代码:
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(logging) .build(); Retrofit retrofit = new Retrofit.Builder() .baseUrl(ApiInterface.BASE_URL) .client(client) .addConverterFactory(GsonConverterFactory.create()) .build();
内容的提问来源于stack exchange,提问作者Tanvi Verma
相关产品推荐
相关产品推荐

