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

如何使用Retrofit2的Interceptor实现请求体(Body)参数加密

嘿,我帮你排查下这个加密拦截器的问题,大概率是几个细节没处理到位导致加密后数据不正确,咱们一步步来理清楚:

可能的问题点及修复建议

  • 加密结果的编码错误
    如果你的encrypt()方法是直接把加密后的二进制字节转成UTF-8字符串,那肯定会出问题——加密后的二进制数据包含很多不可打印的控制字符,直接转UTF-8会丢失或篡改数据。正确的做法是把加密字节用Base64编码成可打印的字符串,这样才能安全地作为文本请求体传输。

  • 请求头未正确同步
    你注释掉了Content-Type和Content-Length的设置,虽然OkHttp在部分场景下会自动处理,但保险起见必须显式更新这些头信息,尤其是当加密后的请求体类型、长度和原请求不一致时,后端很可能因为头信息不匹配无法正确解析请求体。

  • 空请求体的边界处理
    代码里没有判断oldBody是否为空,遇到GET这类没有请求体的请求时会直接抛出空指针异常,得先做非空判断。

修改后的完整代码示例

import android.util.Base64;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import okhttp3.Buffer;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class EncryptionInterceptor implements Interceptor {
    private static final String TAG = EncryptionInterceptor.class.getSimpleName();
    private static final boolean DEBUG = true;

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        RequestBody oldBody = request.body();

        // 处理无请求体的请求(如GET)
        if (oldBody == null) {
            return chain.proceed(request);
        }

        // 读取原请求体内容,通过Buffer保证可重复读取
        Buffer buffer = new Buffer();
        oldBody.writeTo(buffer);
        String strOldBody = buffer.readUtf8();
        buffer.reset(); // 重置buffer,避免影响后续拦截器读取

        // 执行加密:这里假设encrypt接收字节数组,返回加密后的字节数组
        byte[] plainBytes = strOldBody.getBytes(StandardCharsets.UTF_8);
        byte[] encryptedBytes = encrypt(plainBytes);
        // 将加密字节转成Base64字符串,确保传输安全
        String strNewBody = Base64.encodeToString(encryptedBytes, Base64.DEFAULT);

        // 优先沿用原请求的MediaType,避免强制修改导致后端不兼容
        MediaType mediaType = oldBody.contentType() != null 
                ? oldBody.contentType() 
                : MediaType.parse("application/json; charset=utf-8");
        RequestBody newBody = RequestBody.create(mediaType, strNewBody);

        // 重新构建请求,显式更新请求头
        Request newRequest = request.newBuilder()
                .method(request.method(), newBody)
                .header("Content-Type", mediaType.toString())
                .header("Content-Length", String.valueOf(newBody.contentLength()))
                .build();

        return chain.proceed(newRequest);
    }

    // 替换成你实际的加密逻辑(示例用SHA-256模拟,实际换成AES/RSA等)
    private byte[] encrypt(byte[] plainBytes) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            return digest.digest(plainBytes);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return plainBytes;
        }
    }
}

额外注意事项

  1. 和后端确认好加密算法、密钥、编码方式(比如统一用UTF-8),以及请求体是否需要Base64编码,双方逻辑必须完全一致才能正确解密。
  2. 调试时可以打印strOldBody和strNewBody,对比加密前后的内容是否符合预期,也可以抓包查看实际发送的请求体是否正确。
  3. 如果你的encrypt()方法已经返回Base64编码后的字符串,直接使用即可,跳过字节转Base64的步骤。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 09:05:15