Retrofit2.0 公共参数(固定参数)

请先阅读:
Retrofit 动态参数(非固定参数、非必须参数)(Get、Post请求)

在实际项目中,对于有需要统一进行公共参数添加的网络请求,可以使用下面的代码来实现:

RestAdapter restAdapter = new RestAdapter.Builder()                .setEndpoint(ctx).setRequestInterceptor(new RequestInterceptor() {                    @Override                    public void intercept(RequestFacade request) {                        request.addQueryParam("publicParams", "1");                    }                }).setConverter(new BaseConverter())                .build();

在RestAdapter的实例化对象的时候,为其指定一个RequestInterceptor接口的实现类即可,在该类中,可以对请求体的相关参数进行设置,如addHeader、addQueryParam等。

不过遗憾的是Retrofit2.0已经没有了该类,该怎么做呢?通过Interceptor实现。

Interceptor是拦截器, 在发送之前, 添加一些参数, 或者获取一些信息。

/  * 封装公共参数(Key和密码) *  */public class CommonInterceptor implements Interceptor {    private final String mApiKey;    private final String mApiSecret;    public CommonInterceptor(String apiKey, String apiSecret) {        mApiKey = apiKey;        mApiSecret = apiSecret;    }    @Override public Response intercept(Interceptor.Chain chain) throws IOException {        String marvelHash = ApiUtils.generateMarvelHash(mApiKey, mApiSecret);        Request oldRequest = chain.request();        // 添加新的参数        HttpUrl.Builder authorizedUrlBuilder = oldRequest.url()                .newBuilder()                .scheme(oldRequest.url().scheme())                .host(oldRequest.url().host())                .addQueryParameter(MarvelService.PARAM_API_KEY, mApiKey)                .addQueryParameter(MarvelService.PARAM_TIMESTAMP, ApiUtils.getUnixTimeStamp())                .addQueryParameter(MarvelService.PARAM_HASH, marvelHash);        // 新的请求        Request newRequest = oldRequest.newBuilder()                .method(oldRequest.method(), oldRequest.body())                .url(authorizedUrlBuilder.build())                .build();        return chain.proceed(newRequest);    }}

Okhttp3使用了装饰者模式, 使用Builder添加Interceptor。

CommonInterceptor commonInterceptor = new CommonInterceptor(                "key", "Secret");OkHttpClient client = new OkHttpClient.Builder()                .addInterceptor(commonInterceptor)                .build();// 适配器Retrofit retrofit = new Retrofit.Builder()        .baseUrl("url")                     .addConverterFactory(GsonConverterFactory.create()        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())        .client(client)        .build();

有时候你找到了一条线,就能顺着线找到更多。

BasicParamsInterceptor - 为 OkHttp 请求添加公共参数

背景

在 Android Http API 请求开发中经常遇到这样的需求:每一次请求带上一个或者多个固定不变的参数,例如:

  1. 设备唯一标识:device_id = 7a4391e28f309c21

  2. 业务唯一标识:uid = 2231001

  3. 平台类型:platform = android

  4. 客户端版本号:version_code = 6

这些参数是每一次发生请求都需要的,我们姑且称他们为公共参数(或者基础参数)。公共参数一般以 header line、url query 或者 post body(较少) 这些形式插入请求。

实现

如果使用 OkHttp 作为 http request client, 这件事情就变得简单多了。OkHttp 提供了强大的拦截器组件 (Interceptor):

Interceptors are a powerful mechanism that can monitor, rewrite, and retry calls.

也就是说,OkHttp 的拦截器功能之一就是对将要发出的请求进行拦截、改造然后再发出。这正是我们想要的。BasicParamsInterceptor 实现了 okhttp3.Interceptor 接口。

实现 public Response intercept(Chain chain) throws IOException 方法。使用 Builder 模式,暴露以下接口:

addParam(String key, String value)

post 请求,且 body type 为 x-www-form-urlencoded 时,键值对公共参数插入到 body 参数中,其他情况插入到 url query 参数中。

addParamsMap(Map paramsMap)

同上,不过这里用键值对 Map 作为参数批量插入。

addHeaderParam(String key, String value)

在 header 中插入键值对参数。

addHeaderParamsMap(Map headerParamsMap)

在 header 中插入键值对 Map 集合,批量插入。

addHeaderLine(String headerLine)

在 header 中插入 headerLine 字符串,字符串需要符合 -1 != headerLine.indexOf(“:”) 的规则,即可以解析成键值对。

addHeaderLinesList(List headerLinesList)

同上,headerLineList: List 为参数,批量插入 headerLine。

addQueryParam(String key, String value)

插入键值对参数到 url query 中。

addQueryParamsMap(Map queryParamsMap)

插入键值对参数 map 到 url query 中,批量插入。

示例

使用 Buider 模式创建 Interceptor 对象,然后调用 OkHttp 的 addInterceptor(Interceptor i) 方法将 interceptor 对象添加至 client 中:

BasicParamsInterceptor basicParamsInterceptor =        new OkPublicParamsInterceptor.Builder()                .addHeaderParam("device_id", DeviceUtils.getDeviceId())                .addParam("uid", UserModel.getInstance().getUid())                .addQueryParam("api_version", "1.1")                .build();OkHttpClient client = new OkHttpClient.Builder()        .addInterceptor(basicParamsInterceptor)        .build();

TODO

  1. 自动时间戳公共参数的支持

  2. 动态参数的支持(例如登录后插入服务器返回的 uid)
    源码

源码与引用:https://github.com/jkyeo/okht...

basicparamsinterceptor应用

配置基本提交参数

我们可以建一个拦截器,这里我举例加些简单的系统参数,如下:

 class HttpBaseParamsLoggingInterceptor implements Interceptor{        @Override        public Response intercept(Chain chain) throws IOException {            Request request = chain.request();            Request.Builder requestBuilder = request.newBuilder();            RequestBody formBody = new FormBody.Builder()            .add("userId", "10000")            .add("sessionToken", "E34343RDFDRGRT43RFERGFRE")            .add("q_version", "1.1")            .add("device_id", "android-344365")            .add("device_os", "android")            .add("device_osversion","6.0")            .add("req_timestamp", System.currentTimeMillis() + "")            .add("app_name","forums")            .add("sign", "md5")            .build();            String postBodyString = Utils.bodyToString(request.body());            postBodyString += ((postBodyString.length() > 0) ? "&" : "") +  Utils.bodyToString(formBody);            request = requestBuilder                    .post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=UTF-8"),                            postBodyString))                    .build();            return chain.proceed(request);        }    }

上面Utils类是使用的okio.Buffer里面的工具类。通过RequestBody构建要上传的一些基本公共的参数,然后通过”&”符号在http 的body里面其他要提交参数拼接。然后再通过requestBuilder重新创建request对象,然后再通过chain.proceed(request)返回Response 。

接下来在创建OkHttpClient对象的时候修改为如下代码:

mOkHttpClient = new OkHttpClient.Builder()     .addInterceptor(interceptor)     .addInterceptor(new HttpBaseParamsLoggingInterceptor())     .build();

这样就添加好了一些基本的公共参数。

下面我们借助BasicParamsInterceptor实现,代码如下:

public class BasicParamsInterceptor implements Interceptor {    Map queryParamsMap = new HashMap();    Map paramsMap = new HashMap();    Map headerParamsMap = new HashMap();    List headerLinesList = new ArrayList();    private BasicParamsInterceptor() {    }    @Override    public Response intercept(Chain chain) throws IOException {        Request request = chain.request();        Request.Builder requestBuilder = request.newBuilder();        // process header params inject        Headers.Builder headerBuilder = request.headers().newBuilder();        if (headerParamsMap.size() > 0) {            Iterator iterator = headerParamsMap.entrySet().iterator();            while (iterator.hasNext()) {                Map.Entry entry = (Map.Entry) iterator.next();                headerBuilder.add((String) entry.getKey(), (String) entry.getValue());            }        }        if (headerLinesList.size() > 0) {            for (String line: headerLinesList) {                headerBuilder.add(line);            }        }        requestBuilder.headers(headerBuilder.build());        // process header params end        // process queryParams inject whatever it's GET or POST        if (queryParamsMap.size() > 0) {            injectParamsIntoUrl(request, requestBuilder, queryParamsMap);        }        // process header params end        // process post body inject        if (request.method().equals("POST") && request.body().contentType().subtype().equals("x-www-form-urlencoded")) {            FormBody.Builder formBodyBuilder = new FormBody.Builder();            if (paramsMap.size() > 0) {                Iterator iterator = paramsMap.entrySet().iterator();                while (iterator.hasNext()) {                    Map.Entry entry = (Map.Entry) iterator.next();                    formBodyBuilder.add((String) entry.getKey(), (String) entry.getValue());                }            }            RequestBody formBody = formBodyBuilder.build();            String postBodyString = bodyToString(request.body());            postBodyString += ((postBodyString.length() > 0) ? "&" : "") +  bodyToString(formBody);            requestBuilder.post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=UTF-8"), postBodyString));        } else {    // can't inject into body, then inject into url            injectParamsIntoUrl(request, requestBuilder, paramsMap);        }        request = requestBuilder.build();        return chain.proceed(request);    }    // func to inject params into url    private void injectParamsIntoUrl(Request request, Request.Builder requestBuilder, Map paramsMap) {        HttpUrl.Builder httpUrlBuilder = request.url().newBuilder();        if (paramsMap.size() > 0) {            Iterator iterator = paramsMap.entrySet().iterator();            while (iterator.hasNext()) {                Map.Entry entry = (Map.Entry) iterator.next();                httpUrlBuilder.addQueryParameter((String) entry.getKey(), (String) entry.getValue());            }        }        requestBuilder.url(httpUrlBuilder.build());    }    private static String bodyToString(final RequestBody request){        try {            final RequestBody copy = request;            final Buffer buffer = new Buffer();            if(copy != null)                copy.writeTo(buffer);            else                return "";            return buffer.readUtf8();        }        catch (final IOException e) {            return "did not work";        }    }    public static class Builder {        BasicParamsInterceptor interceptor;        public Builder() {            interceptor = new BasicParamsInterceptor();        }        public Builder addParam(String key, String value) {            interceptor.paramsMap.put(key, value);            return this;        }        public Builder addParamsMap(Map paramsMap) {            interceptor.paramsMap.putAll(paramsMap);            return this;        }        public Builder addHeaderParam(String key, String value) {            interceptor.headerParamsMap.put(key, value);            return this;        }        public Builder addHeaderParamsMap(Map headerParamsMap) {            interceptor.headerParamsMap.putAll(headerParamsMap);            return this;        }        public Builder addHeaderLine(String headerLine) {            int index = headerLine.indexOf(":");            if (index == -1) {                throw new IllegalArgumentException("Unexpected header: " + headerLine);            }            interceptor.headerLinesList.add(headerLine);            return this;        }        public Builder addHeaderLinesList(List headerLinesList) {            for (String headerLine: headerLinesList) {                int index = headerLine.indexOf(":");                if (index == -1) {                    throw new IllegalArgumentException("Unexpected header: " + headerLine);                }                interceptor.headerLinesList.add(headerLine);            }            return this;        }        public Builder addQueryParam(String key, String value) {            interceptor.queryParamsMap.put(key, value);            return this;        }        public Builder addQueryParamsMap(Map queryParamsMap) {            interceptor.queryParamsMap.putAll(queryParamsMap);            return this;        }        public BasicParamsInterceptor build() {            return interceptor;        }    }}

只要像上面一样配置就行了。

关键字:java


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部