热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

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

这篇文章主要介绍了Retrofit2.0公共参数(固定参数),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

本文主要介绍了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();

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

背景

在 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/okhttp-basicparamsinterceptor

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) &#63; "&" : "") + 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;
  }

 }
}

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 在项目部署后,Node.js 进程可能会遇到不可预见的错误并崩溃。为了及时通知开发人员进行问题排查,我们可以利用 nodemailer 插件来发送邮件提醒。本文将详细介绍如何配置和使用 nodemailer 实现这一功能。 ... [详细]
  • Windows 7 64位系统下Redis的安装与PHP Redis扩展配置
    本文详细介绍了在Windows 7 64位操作系统中安装Redis以及配置PHP Redis扩展的方法,包括下载、安装和基本使用步骤。适合对Redis和PHP集成感兴趣的开发人员参考。 ... [详细]
  • C#设计模式学习笔记:观察者模式解析
    本文将探讨观察者模式的基本概念、应用场景及其在C#中的实现方法。通过借鉴《Head First Design Patterns》和维基百科等资源,详细介绍该模式的工作原理,并提供具体代码示例。 ... [详细]
  • 嵌入式开发环境搭建与文件传输指南
    本文详细介绍了如何为嵌入式应用开发搭建必要的软硬件环境,并提供了通过串口和网线两种方式将文件传输到开发板的具体步骤。适合Linux开发初学者参考。 ... [详细]
  • 本文介绍了如何利用 Spring Boot 和 Groovy 构建一个灵活且可扩展的动态计算引擎,以满足钱包应用中类似余额宝功能的推广需求。我们将探讨不同的设计方案,并最终选择最适合的技术栈来实现这一目标。 ... [详细]
  • 本教程详细介绍了如何使用 TensorFlow 2.0 构建和训练多层感知机(MLP)网络,涵盖回归和分类任务。通过具体示例和代码实现,帮助初学者快速掌握 TensorFlow 的核心概念和操作。 ... [详细]
  • Spring Boot单元测试中Redis连接失败的解决方案
    本文探讨了在Spring Boot项目中进行单元测试时遇到Redis连接问题的原因及解决方法,详细分析了配置文件加载路径不当导致的问题,并提供了有效的解决方案。 ... [详细]
  • Coursera ML 机器学习
    2019独角兽企业重金招聘Python工程师标准线性回归算法计算过程CostFunction梯度下降算法多变量回归![选择特征](https:static.oschina.n ... [详细]
  • 本文深入分析了 USDC 的稳定性和可能的救援措施,探讨了在硅谷银行破产后 USDC 面临的风险以及行业内的反应。 ... [详细]
  • 基于Node.js、Express、MongoDB和Socket.io的实时聊天应用开发
    本文详细介绍了使用Node.js、Express、MongoDB和Socket.io构建的实时聊天应用程序。涵盖项目结构、技术栈选择及关键依赖项的配置。 ... [详细]
  • 深入解析Java枚举及其高级特性
    本文详细介绍了Java枚举的概念、语法、使用规则和应用场景,并探讨了其在实际编程中的高级应用。所有相关内容已收录于GitHub仓库[JavaLearningmanual](https://github.com/Ziphtracks/JavaLearningmanual),欢迎Star并持续关注。 ... [详细]
  • 本题来自WC2014,题目编号为BZOJ3435、洛谷P3920和UOJ55。该问题描述了一棵不断生长的带权树及其节点上小精灵之间的友谊关系,要求实时计算每次新增节点后树上所有可能的朋友对数。 ... [详细]
  • Nature Microbiology: 人类肠道古菌基因组目录
    本研究揭示了人类肠道微生物群落中古细菌的多样性,分析了来自24个国家、农村和城市人群的1,167个非冗余古细菌基因组。研究鉴定了多个新分类群,并探讨了古菌对宿主的适应性及其与社会人口特征的关系。 ... [详细]
  • 简化报表生成:EasyReport工具的全面解析
    本文详细介绍了EasyReport,一个易于使用的开源Web报表工具。该工具支持Hadoop、HBase及多种关系型数据库,能够将SQL查询结果转换为HTML表格,并提供Excel导出、图表显示和表头冻结等功能。 ... [详细]
  • 本文介绍如何从JSON格式的文件中提取数据并将其分配给Bash脚本中的变量。我们将探讨具体的命令和工具,帮助你高效地完成这一任务。 ... [详细]
author-avatar
暧qs祢生
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有