• Kotlin okhttp3 HttpClient


     之前写过一个 JAVA 版的:
    一次Jackson和泛型的优化和抽象_我去找小伙伴了的博客-CSDN博客一次Jackson和泛型的优化和抽象起因最近在对接供应商的api,由此衍生出了这次优化记录分层:contrller-业务service-gysApiService以下所有的优化都基于gysApiService层的代码:供应商的接口返回的json{"status":200,"msg":"成功","data":null,"stackTrace":null}data数据返回,分两种:返回单个对象(query方法),返回list(queryList方法)。返回单个对象publhttps://blog.csdn.net/fzghjx/article/details/123395263

    现在有需求写了个 Kotlin 的:

     主要分为以下几个类:

    HttpManager:okhttp3 创建过程的封装

    RedirectInterceptor:拦截器,主要针对 307 跳转的重新请求,也可以添加其他的拦截器

    RequstManager:对外提供使用的工具类

    ReponseHandler:请求返回的接口层,具体实现由使用方决定

    1. import okhttp3.Interceptor
    2. import okhttp3.OkHttpClient
    3. import java.util.concurrent.TimeUnit
    4. class HttpManager {
    5. var httpClient: OkHttpClient? = null
    6. val timeUnit: TimeUnit = TimeUnit.SECONDS
    7. val connectTimeOut: Long = 10
    8. val readTimeOut: Long = 10
    9. val writeTimeOut: Long = 10
    10. var interceptors: List<Interceptor> = listOf(RedirectInterceptor())
    11. var networkInterceptors: List<Interceptor> = ArrayList()
    12. companion object {
    13. fun instance() = Holder.INSTANCE
    14. }
    15. private object Holder {
    16. val INSTANCE = HttpManager()
    17. init {
    18. INSTANCE.initHttpClient()
    19. }
    20. }
    21. fun initHttpClient(): OkHttpClient? {
    22. var builder = OkHttpClient.Builder()
    23. .connectTimeout(connectTimeOut, timeUnit)
    24. .readTimeout(readTimeOut, timeUnit)
    25. .writeTimeout(writeTimeOut, timeUnit)
    26. builder = initInterceptor(builder, interceptors)
    27. builder = initNetworkInterceptor(builder, networkInterceptors)
    28. httpClient = builder.build()
    29. return httpClient
    30. }
    31. fun initInterceptor(builder: OkHttpClient.Builder?, interceptors: List<Interceptor>?): OkHttpClient.Builder? {
    32. interceptors?.forEach { i: Interceptor? ->
    33. if (i != null)
    34. builder?.addInterceptor(i)
    35. }
    36. return builder
    37. }
    38. fun initNetworkInterceptor(builder: OkHttpClient.Builder?, networkInterceptors: List<Interceptor>?): OkHttpClient.Builder? {
    39. networkInterceptors?.forEach { i: Interceptor? ->
    40. if (i != null)
    41. builder?.addNetworkInterceptor(i)
    42. }
    43. return builder
    44. }
    45. }

     

    1. import okhttp3.Interceptor
    2. import okhttp3.Request
    3. import okhttp3.Response
    4. import org.slf4j.Logger
    5. import org.slf4j.LoggerFactory
    6. import javax.servlet.http.HttpServletResponse.SC_TEMPORARY_REDIRECT
    7. class RedirectInterceptor : Interceptor {
    8. val logger: Logger = LoggerFactory.getLogger(RedirectInterceptor::class.java)
    9. override fun intercept(chain: Interceptor.Chain): Response {
    10. val request = chain.request()
    11. var response = chain.proceed(request)
    12. val code = response.code()
    13. if (code == SC_TEMPORARY_REDIRECT) {
    14. //获取重定向的地址
    15. val location = response.headers()["Location"]
    16. logger.info("重定向地址:", "location = $location")
    17. //重新构建请求
    18. val newRequest: Request = request.newBuilder().url(location).build()
    19. response = chain.proceed(newRequest)
    20. }
    21. return response
    22. }
    23. }
    1. import com.google.common.base.Strings
    2. import okhttp3.FormBody
    3. import okhttp3.Interceptor
    4. import okhttp3.MediaType
    5. import okhttp3.OkHttpClient
    6. import okhttp3.Request
    7. import okhttp3.RequestBody
    8. class RequestManager {
    9. var okHttpClient: OkHttpClient? = null
    10. var builder: Request.Builder? = null
    11. init {
    12. builder = Request.Builder()
    13. }
    14. constructor() {
    15. okHttpClient = HttpManager.instance().httpClient
    16. }
    17. constructor(okHttpClient: OkHttpClient?) {
    18. if (okHttpClient == null)
    19. RequestManager()
    20. else
    21. this.okHttpClient = okHttpClient
    22. }
    23. fun doGet(url: String, headers: MutableMap<String, String>? = null, params: MutableMap<String, String>? = null): RequestManager {
    24. if (url.isBlank())
    25. return this
    26. if (headers != null)
    27. addHeaders(headers)
    28. builder!!.url(if (params != null) setGetParams(url, params) else url).get()
    29. return this
    30. }
    31. fun doPost(url: String, headers: MutableMap<String, String>? = null, params: MutableMap<String, String>? = null): RequestManager {
    32. if (url.isBlank())
    33. return this
    34. if (headers != null)
    35. addHeaders(headers)
    36. builder!!.url(url)
    37. builder!!.post(setPostParams(params))
    38. return this
    39. }
    40. fun doPut(url: String, headers: HashMap<String, String>? = null, content: String?): RequestManager {
    41. if (url.isBlank())
    42. return this
    43. if (headers != null)
    44. addHeaders(headers)
    45. builder!!.url(url)
    46. var requestBody = setPutBody(content)
    47. if (requestBody != null) {
    48. builder!!.put(requestBody)
    49. }
    50. return this
    51. }
    52. fun addHeaders(headers: MutableMap<String, String>) {
    53. headers.entries.forEach { entry ->
    54. headers.keys
    55. builder?.addHeader(entry.key, entry.value)
    56. }
    57. }
    58. fun setGetParams(url: String, params: MutableMap<String, String>): String {
    59. var sb = StringBuilder(url)
    60. if (params.isNotEmpty()) sb.append("?") else sb
    61. params.forEach { entry ->
    62. params.keys
    63. sb.append(entry.key + "=" + entry.value + "&")
    64. }
    65. return if (sb.toString().endsWith("&")) sb.subSequence(0, sb.lastIndex).toString() else sb.toString()
    66. }
    67. fun setPostParams(params: MutableMap<String, String>?): RequestBody? {
    68. var builder = FormBody.Builder()
    69. params?.forEach { entry ->
    70. params.keys
    71. builder.add(entry.key, entry.value)
    72. }
    73. return builder.build()
    74. }
    75. fun setPutBody(content: String?): RequestBody? {
    76. if (Strings.isNullOrEmpty(content)) {
    77. return null
    78. }
    79. return RequestBody.create(MediaType.parse("application/json"), content)
    80. }
    81. fun <T> execute(responseHandler: ResponseHandler<T>): T? {
    82. val response = okHttpClient!!.newCall(builder!!.build()).execute()
    83. return responseHandler.apply(response)
    84. }
    85. }
    1. import okhttp3.Response
    2. interface ResponseHandler<T> {
    3. fun apply(response: Response): T
    4. }

    以下是使用方的代码,返回结果是 Result<List<T>> 和 Result<T> 的格式,所以针对两种返回,写了两个不同的 JavaType, 用于 Jackson 的反序列化使用,避免因为泛型导致反序列化嵌套 json 数据的内层数据为 LinkedHaspMap 

    1. fun <T> fromClass(inner: Class<T>): BaseResponseHandler<T> {
    2. return BaseResponseHandler(JsonUtil.getObjectMapper().typeFactory.constructType(inner))
    3. }
    4. fun <T> fromListClass(inner: Class<T>): BaseResponseHandler<List<T>> {
    5. return BaseResponseHandler(JsonUtil.getObjectMapper().typeFactory.constructParametricType(List::class.java, inner))
    6. }
    7. class BaseResponseHandler<T>(javaType: JavaType) : ResponseHandler<Result<T>> {
    8. private var javaType: JavaType
    9. init {
    10. this.javaType = JsonUtil.getObjectMapper().typeFactory.constructParametricType(Result::class.java, javaType)
    11. }
    12. override fun apply(response: okhttp3.Response): Result<T> {
    13. return JsonUtil.getObjectMapper().readValue(response.body()!!.string(), javaType)
    14. }
    15. }

     使用方调用:

            var imageVersion = RequestManager().doGet(host + vhost.common + instance.getVersionByIp, null, mutableMapOf(Pair("ip", heartbeatInfo.agentIp))).execute(fromClass(String::class.java))?.data
    
           var idleInstanceFromVhost = RequestManager().doGet(host + vhost.common + instance.getIdleInstanceByImageVersion, null, mutableMapOf(Pair("projectEnv", "ue-" + env), Pair("imageVersion", imageVersion ?: ""))).execute(fromListClass(InstanceListResp::class.java))?.data

  • 相关阅读:
    【Java】Deque接口与List接口中的remove方法
    【通信系列4 -- 基站定位】
    Redis的持久化方式各有什么优点?
    【晶振专题】案例:晶振供应商提供的晶振匹配测试报告能看出什么?
    会议OA项目之我的会议(会议排座&送审)
    蓝桥杯2022年第十三届决赛真题-背包与魔法
    GitHub要求开启2FA,否则不让用了。
    【C语言】全面解析结构体,结构体知识点整理
    Spring Boot Logging 配置
    资源道具化
  • 原文地址:https://blog.csdn.net/fzghjx/article/details/125413608