You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Retrofit 2发送JsonObject?遇无响应及加解密异常问题

解决接口调用的两个问题:请求格式错误 & BadPaddingException

咱们一步步来拆解你遇到的两个问题,帮你搞定这个接口调用的麻烦:

问题1:后端收到NameValuePairs而非预期JSON

你用org.json.JSONObject作为Retrofit的@Body参数时,后端收到的是表单格式的NameValuePairs,这是因为Retrofit默认会把org.json.JSONObject当成表单数据处理,而不是JSON格式的请求体。

解决方案

要让Retrofit正确发送JSON请求,得做两个调整:

  1. 确保你的Retrofit实例配置了Gson转换器(这是处理JSON请求/响应的核心):
val retrofit = Retrofit.Builder()
    .baseUrl("你的基础URL")
    .addConverterFactory(GsonConverterFactory.create())
    .client(你的OkHttpClient实例)
    .build()
  1. 改用Gson的JsonObject或者类型安全的数据类作为请求体参数:
    • 用Gson JsonObject的方式:
    @POST("getRequest")
    Call<GenericWrapper> generic(@Body com.google.gson.JsonObject jsonObject);
    
    • 更推荐的类型安全方式(创建请求数据类):
    data class InitSessionRequest(
        @SerializedName("dt") val dt: String
    )
    
    然后修改ApiService:
    @POST("getRequest")
    Call<GenericWrapper> generic(@Body InitSessionRequest request);
    

这样调整后,Retrofit就会把请求体序列化为标准JSON格式,后端就能正确接收了。

问题2:改用Gson JsonObject后出现BadPaddingException

这个异常几乎都是加密解密流程不匹配导致的,咱们逐一排查可能的原因:

排查点1:AES加密/解密的配置完全一致吗?

必须确保客户端和后端的AES模式、填充方式、密钥长度完全相同。比如客户端加密用的是AES/CBC/PKCS5Padding,后端解密也得用一模一样的配置,不能一端用PKCS7Padding另一端用NoPadding(Java里PKCS5和PKCS7其实是兼容的,但最好统一)。

检查你的AesUtil实现,比如加密方法应该是这样的:

public String encrypt(byte[] data) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    SecretKeySpec secretKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
    IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes("UTF-8"));
    cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
    byte[] encryptedBytes = cipher.doFinal(data);
    // 加密后一定要转成Base64字符串,不能直接用new String(encryptedBytes)(会乱码丢数据)
    return Base64.encodeToString(encryptedBytes, Base64.NO_WRAP);
}

解密方法也要对应:

public byte[] decrypt(byte[] encryptedData) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    SecretKeySpec secretKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
    IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes("UTF-8"));
    cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
    return cipher.doFinal(encryptedData);
}

排查点2:加密解密的步骤顺序是否完全对称?

你的客户端加密流程是:
原始JSON → 字符串 → UTF-8字节 → Base64编码(NO_WRAP) → AES加密 → Base64编码(得到dt字段)
那后端的解密流程必须是:
dt字段 → Base64解码 → AES解密 → Base64解码 → UTF-8字符串 → 解析JSON
任何一步顺序错了都会导致解密失败,比如后端如果跳过了Base64解码直接解密,就会抛出BadPaddingException。

排查点3:密钥和IV的一致性

检查你加密用的aesKeyIv.getKey()、aesKeyIv.getInitVector(),和解密时用的apiSingleton.getIv()、apiSingleton.getKey()是否完全一致:

  • 有没有在传输过程中被修改?比如后端返回的IV是Base64编码的,你是不是直接当成UTF-8字符串用了?需要先Base64解码再转字节数组。
  • 转字节数组时的编码是不是统一用UTF-8?不能一端用UTF-8另一端用默认编码。

排查点4:Base64编码/解码的参数一致

客户端加密前用的是Base64.NO_WRAP,解密后端返回的dt时也是用Base64.NO_WRAP吗?要确保两端的Base64编码规则完全一致(比如是否换行、是否加填充符)。

总结

先搞定请求格式的问题(配置Gson转换器+用Gson JsonObject/数据类),再逐一排查加密解密的配置、步骤、密钥IV的一致性,就能解决这两个问题啦。

内容的提问来源于stack exchange,提问作者user6683139

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:46:32