Retrofit 拦截器-基础公共参数拦截器实现

为了紧跟潮流,之前在公司新开项目中设计使用了MVP+Retrofit+Dagger2模式的开发框架,但由于当时时间紧,任务重。尝试去通过拦截器添加基础参数,但是POST请求一直不成功,最终无奈放弃,使用了最Low的方式,GET,POST请求全部是用@QueryMap注解来添加请求参数,然后将基础参数封装一个公共的方法,每次请求接口时调用。这也成为了我心中一直的一个梗,久久不能释怀。后来曾多次尝试解决,一直不得其法,今天终于解决了!!!并在发现了是一个极其低级的错误,反思还是自己对Retrofit没有去了解,连基本用法也用的马马虎虎。特此记录!

废了这么多话,现在开始重点!

App在与后台交互时,通常会存在一些基础公共的请求参数,比如 "用户Id",“版本号”,“平台号”等等;这些参数是任何接口请求都会添加的请求参数。这种重复代码工作,我们首先想到的肯定就是使用拦截器。而Retrofit这种优秀的网络请求框架就支持众多功能强大拦截器,主要包括请求前操作拦截器(对Request 参数进行处理)和请求后操作拦截器(对Response数据进行处理)。

今天主要介绍一下请求前操作拦截器-添加基础公共参数拦截器实现

/**
 * Retrofit 基本参数拦截器
 */
public class CommonParamInterceptor implements Interceptor {

    /**
     * 请求方法-GET
     */
    private static final String REQUEST_METHOD_GET = "GET";

    /**
     * 请求方法POST
     */
    private static final String REQUEST_METHOD_POST = "POST";

    /**
     * 基础参数-平台号
     */
    private static final String REQUEST_COMMON_PARAM_PLATFORM = "2";

    /**
     * 基础参数-个体户Id
     */
    private static final String REQUEST_COMMON_PARAM_PERSONALID = "0";

    /**
     * 基础参数-未登录 userId
     */
    private static final String REQUEST_COMMON_PARAM_USERID_DEFAULT = "0";

    /**
     * 基础参数-未登录 token
     */
    private static final String REQUEST_COMMON_PARAM_TOKEN_DEFAULT = "";

    @Override
    public Response intercept(Chain chain) throws IOException {

        //获取原先的请求对象
        Request request = chain.request();
        if (REQUEST_METHOD_GET.equals(request.method())) {
            request = addGetBaseParams(request);
        } else if (REQUEST_METHOD_POST.equals(request.method())) {
            request = addPostBaseParams(request);
        }
        return chain.proceed(request);
    }


    /**
     * 添加GET方法基础参数
     *
     * @param request
     * @return
     */
    private Request addGetBaseParams(Request request) {

        HttpUrl httpUrl = request.url()
                .newBuilder()
                .addQueryParameter("platform", REQUEST_COMMON_PARAM_PLATFORM)//平台号
                .addQueryParameter("version", ToolHelper.getVersionName())//版本号
                .addQueryParameter("enterpriseId", FSaveData.Login.getEnterpriseId())//企业Id
                .addQueryParameter("personalId", REQUEST_COMMON_PARAM_PERSONALID)//个体户id
                .build();

        //根据登录状态添加userId&&token
        if (ToolHelper.logined()) {
            httpUrl = httpUrl.newBuilder()
                    .addQueryParameter("userId", FSaveData.Login.getUserId())
                    .addQueryParameter("token", FSaveData.Login.getToken())
                    .build();
        } else {
            httpUrl = httpUrl.newBuilder()
                    .addQueryParameter("userId", REQUEST_COMMON_PARAM_USERID_DEFAULT)
                    .addQueryParameter("token", REQUEST_COMMON_PARAM_TOKEN_DEFAULT)
                    .build();
        }

        //添加签名
        Set<String> nameSet = httpUrl.queryParameterNames();
        ArrayList<String> nameList = new ArrayList<>();
        nameList.addAll(nameSet);
        Map<String, Object> paramMap = new HashMap<>();
        for (int i = 0; i < nameList.size(); i++) {
            paramMap.put(nameList.get(i), httpUrl.queryParameterValue(i));
        }
        httpUrl = httpUrl.newBuilder().addQueryParameter("sign", ToolHelper.dataSignature(paramMap)).build();

        request = request.newBuilder().url(httpUrl).build();
        return request;
    }

    /**
     * 添加POST方法基础参数
     *
     * @param request
     * @return
     */
    private Request addPostBaseParams(Request request) {

        /**
         * request.body() instanceof FormBody 为true的条件为:
         * 在ApiService 中将POST请求中设置
         * 1,请求参数注解为@FieldMap
         * 2,方法注解为@FormUrlEncoded
         */
        if (request.body() instanceof FormBody) {
            FormBody formBody = (FormBody) request.body();
            FormBody.Builder builder = new FormBody.Builder();

            for (int i = 0; i < formBody.size(); i++) {
                //@FieldMap 注解 Map元素中 key 与 value 皆不能为null,否则会出现NullPointerException
                if (formBody.value(i) != null)
                    builder.add(formBody.name(i), formBody.value(i));
            }

            builder
                    .add("platform", REQUEST_COMMON_PARAM_PLATFORM)//平台
                    .add("version", ToolHelper.getVersionName())//版本号
                    .add("enterpriseId", FSaveData.Login.getEnterpriseId())//企业Id
                    .add("personalId", REQUEST_COMMON_PARAM_PERSONALID);//个体户id


            //根据登录状态添加userId&&token
            if (ToolHelper.logined()) {
                builder
                        .add("userId", FSaveData.Login.getUserId())
                        .add("token", FSaveData.Login.getToken());
            } else {
                builder
                        .add("userId", REQUEST_COMMON_PARAM_USERID_DEFAULT)
                        .add("token", REQUEST_COMMON_PARAM_TOKEN_DEFAULT);
            }

            //添加签名
            Map<String, Object> paramMap = new HashMap<>();
            formBody = builder.build();
            for (int i = 0; i < formBody.size(); i++) {
                paramMap.put(formBody.name(i), formBody.value(i));
            }
            formBody = builder
                    .add("sign", ToolHelper.dataSignature(paramMap))
                    .build();

            request = request.newBuilder().post(formBody).build();
        }
        return request;
    }

}



如代码注释所言,我所犯下的低级错误就是,无论GET,还是POST请求,全部都是用了@QueryMap参数注解,而@Query,@QueryMap仅仅是Retrofit中对@GET注解提供的请求参数注解。@POST注解合适的是@Field 和 @FieldMap注解,否则POST方式下 

request.body() instanceof FormBody

永远都为fasle!!!


正确使用@GET,@POST:

    @GET("mobileVerify")
    Observable<CheckPhoneBean> checkPhone(@QueryMap Map<String, Object> stringObject);

    @POST("register")
    @FormUrlEncoded
    Observable<RegisterResponse> register(@FieldMap Map<String, Object> map);


Retrofit2 注解相关请参考:Retrofit2 ,Dagger2等常用框架注解功能介绍


最后为Retrofit添加拦截器

/**
 * 获取全局Retrofit实例对象
 * 用于非集成公共基类BaseActivity && BaseFragment情况下进行网络请求使用
 * 采用Double Check Lock 单例模式
 * 添加超时时间&&基础公共参数拦截器&&网络请求返回信息打印拦截器
 */
public class RetrofitHelpter {

    private static final int TOME_OUT = 100; //超时时间

    private static Retrofit mInstance = null;

    private RetrofitHelpter() {
    }

    /**
     * 提供Retrofit实例对象
     * DCL单例模式
     *
     * @return
     */
    public static Retrofit getInstance() {
        if (mInstance == null) {
            synchronized (Retrofit.class) {
                if (mInstance == null) {
                    mInstance = new Retrofit.Builder()
                            .baseUrl(API.BASE_URL)
                            .client(providerOkHttpClient())
                            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//使用rxjava
                            .addConverterFactory(GsonConverterFactory.create())//使用Gson
                            .build();
                }
            }
        }
        return mInstance;
    }

    /**
     * 提供OkhttpClient实例对象
     *
     * @return
     */
    private static OkHttpClient providerOkHttpClient() {
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .connectTimeout(TOME_OUT, TimeUnit.SECONDS)
                .readTimeout(TOME_OUT, TimeUnit.SECONDS)
                .addNetworkInterceptor(providerNetworkInterceptor())
                .addInterceptor(providerInterceptor());

        return builder.build();
    }

    /**
     * 提供网络请求返回信息打印拦截器
     *
     * @return
     */
    private static Interceptor providerNetworkInterceptor() {
        return new RequestIntercept(null);
    }

    /**
     * 基础公共参数拦截器
     *
     * @return
     */
    private static Interceptor providerInterceptor() {
        return new CommonParamInterceptor();
    }
}

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: 你可以使用OkHttp的Interceptor来拦截参数。在使用Retrofit时,可以通过自定义OkHttpClient并添加Interceptor来实现。以下是一个示例: ``` OkHttpClient okHttpClient = new OkHttpClient.Builder() .addInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request originalRequest = chain.request(); Request requestWithNewParameter = originalRequest.newBuilder() .addHeader("Your-Header-Name", "Your-Header-Value") .build(); return chain.proceed(requestWithNewParameter); } }) .build(); Retrofit retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build(); YourApiService apiService = retrofit.create(YourApiService.class); ``` 在上面的示例中,我们添加了一个Interceptor来拦截每个请求并添加一个自定义的Header。你可以根据需要修改拦截器实现来拦截并修改请求参数。 ### 回答2: 在Android开发中,Retrofit是一个非常流行的网络请求库。它提供了拦截器(Interceptor)的功能,可以对网络请求的参数进行拦截和修改。 拦截器是一个接口,可以在请求之前或者响应之后对请求进行处理。在Retrofit中,可以通过实现Interceptor接口来自定义拦截器。 通过拦截器,我们可以对请求进行一些通用的处理,比如对请求头进行添加、修改、删除等操作。我们可以在拦截器的intercept方法中获取到请求的参数,然后根据需求进行修改。 拦截器可以被添加到OkHttpClient的拦截器链中,通过addInterceptor()方法来添加。当发起网络请求时,拦截器会按照添加的顺序进行拦截。这样,我们就可以在请求中添加或修改参数拦截器还可以对响应进行处理,比如对返回的数据进行解析、转换等操作。拦截器可以获取到响应的数据,然后可以对数据进行一些处理,并返回给调用方。 通过使用拦截器,我们可以在不修改原有的网络请求代码的情况下,对请求和响应进行一些通用的处理。这样可以提高开发的效率,并且可以保持代码的整洁和可维护性。 总的来说,Android Retrofit拦截器功能非常强大,可以非常方便地对网络请求的参数进行拦截和修改,提供了非常灵活的扩展性。 ### 回答3: 在Android中,Retrofit是一个广泛使用的网络请求库,用于方便地从服务器获取数据。拦截参数是指在使用Retrofit发送网络请求之前,可以通过拦截器对请求的参数进行修改或添加一些额外的信息。 在Retrofit中,可以通过自定义拦截器实现参数的拦截操作。拦截器是一个接口,它提供了两个方法:intercept和proceed。 intercept方法用于处理拦截逻辑,我们可以在这个方法中获取到请求的参数信息,并对其进行修改或添加额外信息。可以使用request.body()方法获取请求体,再通过request.newBuilder()方法创建一个新的请求,最后通过chain.proceed()方法继续请求的发送。 proceed方法表示继续发送原始请求,如果不调用该方法,请求将会被拦截,不会发送到服务器。 要使用拦截器,首先需要创建一个OkHttpClient对象,并通过addInterceptor方法将拦截器添加到OkHttpClient中。然后将创建的OkHttpClient对象传递给Retrofit.Builder的client方法。 以下是一个示例代码,演示如何使用拦截器对请求参数进行拦截: ``` OkHttpClient.Builder builder = new OkHttpClient.Builder(); builder.addInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); // 获取原始请求的参数 HttpUrl url = request.url().newBuilder() .addQueryParameter("key", "value") .build(); Request newRequest = request.newBuilder() .url(url) .build(); return chain.proceed(newRequest); } }); OkHttpClient client = builder.build(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://example.com/") .client(client) .build(); ``` 上述代码创建了一个OkHttpClient对象,并添加了一个拦截器。在拦截器的intercept方法中,获取了原始请求的参数,然后对其进行了修改(添加了一个名为key值为value的参数),最后调用chain.proceed方法继续发送请求。 通过拦截器,我们可以对请求的参数进行灵活处理,例如对请求进行签名、添加公共参数等操作,提高了开发的灵活性和效率。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值