【问题标题】:Retrofit 2 : Custom annotations for custom interceptorRetrofit 2:自定义拦截器的自定义注解
【发布时间】:2018-05-25 10:39:59
【问题描述】:

我有用于身份验证的自定义拦截器:

@Named("authInterceptor")
    @Provides
    @Singleton
    fun providesAuthInterceptor(preferencesManager: PreferencesManager): Interceptor {
        return Interceptor { chain ->
            val newBuilder = chain.request().newBuilder()
            newBuilder.addHeader("access-token", preferencesManager.getAccessToken())
            val request = newBuilder.build()
            return@Interceptor chain.proceed(request)
        }
    }

但我有一些不需要身份验证标头的调用。

我希望在我的服务中拥有的是:

interface NetService {
    @NEEDAUTH
    @GET("users")
    fun getAllShops(key: String): Single<SomeResponse>

    @FormUrlEncoded
    @POST("users")
    fun register(@Field("nickname") nickname: String): Single<SomeResponse>
}

所以,第一个调用将使用 authInterceptor,第二个不会使用它。

【问题讨论】:

  • 请分享代码,如果你至少得到了答案或一些提示

标签: android retrofit2 interceptor okhttp3


【解决方案1】:

从Retrofit 2.6.0版本开始,OkHttp Interceptor中的注解可以通过tag字段这样获取:

response.request.tag(Invocation::class.java)?.method()?.getAnnotation(YourAnnotation::class.java)

然后在拦截器内部,可以验证请求是否带注释。

改造变更日志:

新增:@Tag 参数注释,用于在底层 OkHttp 请求对象上设置标签。这些可以在 CallAdapters 或 OkHttp 拦截器中读取,用于跟踪、分析、变化行为等。

https://github.com/square/retrofit/pull/2899/files

【讨论】:

    【解决方案2】:

    我有类似的需求,我发现Annotation可以在Converter.Factory:requestBodyConverter()中读取, Converter.Factory:responseBodyConverter()CallAdapter.Factory.get()

    我还找到了两篇文章作为每种方式的实施示例。

    1. 使用转换器:Auto Caching with Retrofit

    我们将使用 Retrofit 提供的 gson 转换器 (GsonConverterFactory) 并稍微修改它以在 GsonResponseBodyConverter.class 中包含一个侦听器来处理 http 响应解析。

    GsonCacheableConverter 中,它会覆盖responseBodyConverter() 以保留带有@Cacheable 标记的响应。

    1. 使用 CallAdapter:Custom Annotations with Retrofit 2

    我们读取 CallAdapter.Factory 中的注解,当在 CallAdapter 中创建请求时,我们会将此类请求的一些信息存储在某个映射中,以便稍后在某个拦截器中识别它。

    它使用自定义的CallAdapter来获取注解@Authenticated,并将数据放入一个map中,然后在Interceptor中解析。

    我认为requestBodyConverter()CallAdapter 更接近您的要求。

    如果你不坚持自定义注解,我认为目前最简单的方法是在 api 接口中添加自定义标头,然后在拦截器中读取并删除它。

    即在你的服务中添加@Headers("needauth: 1"),并使用chain.request().header("needauth")获取值。

    例如:Sneaking Data into an OkHttp Interceptor

    【讨论】:

    • 鼓励链接到外部资源,但请在链接周围添加上下文,以便您的其他用户了解它是什么以及为什么存在。始终引用重要链接中最相关的部分,以防目标站点无法访问或永久离线。见how to answer
    【解决方案3】:

    Interceptors 是存在于OkHttp 中的概念,Retrofit 对此一无所知。

    您需要做的是拥有两个 OkHttp 客户端,以及它们各自的 Retrofit 实例。

    • 一个带有身份验证标头的
    • 剩下的一个

    您是否需要身份验证标头将决定注入哪个实例。

    【讨论】:

    • 我知道那个解决方案,这样就有可能在一个存储库类中有两个客户端。我不喜欢那样。我认为这应该在服务接口的范围内。
    • 你定义事物的范围,只是从 OkHttp 客户端实例中抽象出一切。
    【解决方案4】:

    基于Max Cruz answer。确实尝试在那里发表评论,但它看起来太丑了,因为不知道如何制作多行。

    我作为扩展函数使用:

    fun &lt;T : Annotation&gt; Request.getCustomAnnotation(annotationClass: Class&lt;T&gt;): T? = this.tag(Invocation::class.java)?.method()?.getAnnotation(annotationClass)

    然后你可以这样使用:

    request.getCustomAnnotation(YourAnnotation::class.java)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-26
      • 1970-01-01
      • 2016-05-31
      • 2020-10-11
      • 1970-01-01
      • 1970-01-01
      • 2019-01-14
      相关资源
      最近更新 更多