后台接口返回数据乱码,Retrofit配置headers无效处理办法

本文介绍了一种解决第三方接口返回非UTF-8编码导致的数据乱码问题的方法。通过实现一个自定义的OkHttp拦截器,该拦截器能够将非标准编码的数据转换为UTF-8编码,并进行必要的解密处理。


之前在跟三方公司做接口对接是最蛋疼的,各种不规范,连ContentType类型都不是UTF-8,所以返回的
信息就蛋疼了,乱码了,更蛋疼的他就不改了。。。。。。。。那怎么办呢。。。。。。。。。。。。。
第一步、配置一个拦截器:
import android.content.Context;
import android.util.Log;

import java.io.IOException;
import java.nio.charset.Charset;

import okhttp3.Headers;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
import okio.GzipSource;


/**
 *
 * @author J.query
 * @date 2021/6/16
 * @email j-query@foxmail.com
 * @Description:
 *
 */
public class HeaderInterceptor implements Interceptor {

    private static final String TAG = "HeaderInterceptor";

    private Context context;

    public HeaderInterceptor(Context context) {
        this.context = context;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        ResponseBody responseBody = null;
        Request original = chain.request();
        Response response = chain.proceed(original);
        try {
            MediaType contentType = responseBody.contentType();
            String query = bufferBody(response);
            Log.e(TAG, "解密前数据contentType====》${contentType}");
            Log.e(TAG, "解密前数据====》${query}");
            //数据加密工具(可忽略)
            DESUtils des = new DESUtils(SECRET_KEY); // 加密代码
            String responseData = des.decrypt(query);
            responseBody = ResponseBody.create(MediaType.parse("application/json;charset=UTF-8"), responseData.trim());
        } catch (Exception e) {
            e.printStackTrace();
        }
        Log.e(TAG, "解密后数据====》${responseData}");
        response = response.newBuilder()
                .addHeader("Content-Type", "application/json")
                .body(responseBody)
                .build();
        return response;
    }

    private String bufferBody(Response response) throws IOException {
        Headers headers = response.headers();
        ResponseBody responseBody = response.body();
        BufferedSource source = responseBody.source();
        source.request(Long.MAX_VALUE); // Buffer the entire body.
        Buffer buffer = source.buffer();
        // 判断是否有压缩
        if ("gzip".equalsIgnoreCase(headers.get("Content-Encoding"))) {
            GzipSource gzippedResponseBody = null;
            try {
                gzippedResponseBody = new GzipSource(buffer.clone());
                buffer = new Buffer();
                buffer.writeAll(gzippedResponseBody);
            } finally {
                if (gzippedResponseBody != null) {
                    gzippedResponseBody.close();
                }
            }
        }
        return buffer.clone().readString(Charset.forName("UTF-8"));
    }
}

第二步、在App初始化网络配置信息


    OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
    if (BuildConfig.DEBUG) {
        HttpLoggingInterceptorM interceptor = setLogInterceptor();//日志拦截器
        interceptor.setLevel(HttpLoggingInterceptorM.Level.BODY);
        builder.addInterceptor(interceptor);
    }
    builder.connectTimeout(10, TimeUnit.SECONDS)
            //关键代码(测试Interceptor(new HeaderInterceptor(this))这样也是可以的)
            .addNetworkInterceptor(new HeaderInterceptor(this))//添加header拦截器
            .sslSocketFactory(getSSLFactory(), xtm)
            .hostnameVerifier(DO_NOT_VERIFY);
    OkHttpClient client = builder.build();
  
关键看图,返回的数据是UTF-8了。

<think>好的,用户想知道如何在Retrofit中动态添加headers,并且需要示例代码。首先,我需要回忆Retrofit中添加请求头的几种方法。根据之前的知识,Retrofit通常有几种方式:使用@Headers注解、使用Interceptor拦截器,或者通过OkHttpClient来添加。 用户特别提到“动态添加”,所以@Headers注解可能不太适合,因为它是静态的,编译时确定的。动态的话,可能需要用到拦截器或者使用@Header参数。 然后,我记得引用里的内容,比如引用[2]提到了@Headers注解的使用,可以添加单个或多个请求头。但这是静态的。动态的话,引用[3]提到了拦截器的使用,比如日志拦截器,通过OkHttpClient的Builder添加。所以动态添加headers可能需要拦截器,在拦截器中修改请求,添加需要的header。 另外,用户可能需要不同的方式,比如有些header是每个请求都需要,有些是特定请求需要。动态可能指运行时根据条件添加,比如根据用户登录状态添加Authorization头。 所以可能的解决方案有两种:一种是使用拦截器统一添加动态headers,另一种是在接口方法中使用@Header注解参数,让调用者传入。 接下来需要整理这两种方法的示例代码。比如,使用拦截器的话,需要创建OkHttpClient实例,添加拦截器,然后在拦截器的intercept方法中往request中添加header。然后把这个client设置Retrofit.Builder里。 另一种方法是在接口方法中,使用@Header作为参数,这样每次调用方法时传入不同的值。 然后检查用户提供的引用内容是否有相关例子。引用[2]中的@Headers是静态的,引用[3]中的拦截器是添加日志的例子,但可以类似地修改来添加headers。所以动态添加可能需要拦截器,或者在方法参数中使用@Header。 需要确保示例代码正确,符合Retrofit的最新用法。比如,Interceptor的正确实现,使用addInterceptor还是addNetworkInterceptor,但通常添加通用header用addInterceptor就可以了。 总结步骤:1. 使用拦截器动态添加全局header;2. 使用@Header参数针对单个请求动态添加。两种方法的示例代码都要给出,并说明适用场景。 另外,要注意用户可能需要明确的代码示例,所以需要写出具体的Java或Kotlin代码,比如如何创建拦截器,如何添加到OkHttpClient,然后在Retrofit中使用这个client。 还需要注意代码格式是否正确,比如Builder的链式调用,正确导入相关类,比如OkHttpClient、Interceptor等。可能还需要提到如何根据条件动态添加不同的header值,比如从SharedPreferences中获取token。 最后,确保回答结构清晰,分点说明不同的方法,并给出示例代码,引用相关的参考资料,比如引用[2]和[3]中的内容,说明拦截器的使用和@Headers的区别。</think>在 Retrofit 中动态添加请求头有以下两种常用方法,分别适用于不同场景: --- ### 方法一:通过拦截器动态添加全局请求头 适用于**所有请求都需要携带的公共请求头**(如认证 Token、设备信息),通过自定义拦截器实现: ```java // 创建拦截器 Interceptor headerInterceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request originalRequest = chain.request(); // 动态添加请求头(例如从本地存储获取 Token) String token = SharedPreferencesUtils.getToken(); Request newRequest = originalRequest.newBuilder() .header("Authorization", "Bearer " + token) // 动态值 .header("User-Agent", "Android/1.0") // 固定值 .build(); return chain.proceed(newRequest); } }; // 配置 OkHttpClient OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(headerInterceptor) .build(); // 构建 Retrofit 实例 Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.example.com/") .client(client) .addConverterFactory(GsonConverterFactory.create()) .build(); ``` --- ### 方法二:通过 @Header 注解动态添加单个请求头 适用于**特定接口需要动态传递不同值**的请求头(如临时验证码、版本号): ```java // 接口定义 public interface ApiService { @GET("user/profile") Call<ResponseBody> getProfile( @Header("X-Request-ID") String requestId // 动态请求头参数 ); } // 调用示例 String dynamicRequestId = UUID.randomUUID().toString(); apiService.getProfile(dynamicRequestId).enqueue(...); ``` --- ### 两种方法对比 | 方法 | 优点 | 适用场景 | |------------|-------------------------|-----------------------| | 拦截器 | 集中管理,避免重复代码 | 全局固定/动态请求头 | | @Header | 灵活控制单个接口 | 临时或差异化的请求头 | --- ### 注意事项 1. **优先级**:若同时使用两种方法,`@Header` 注解的请求头会覆盖拦截器添加的同名请求头[^2] 2. **敏感信息**:避免在拦截器中硬编码敏感信息(如 API Key),建议通过环境变量或配置中心获取 3. **性能优化**:频繁变化的请求头建议使用 `@Header`,避免拦截器逻辑复杂化[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值