代码之家  ›  专栏  ›  技术社区  ›  Andrew Arrow

如何使OkHttp从Jersey中获取参数并在拦截器中使用?

  •  1
  • Andrew Arrow  · 技术社区  · 7 年前

    我可以在泽西岛买到这个饼干。问题是当我想要涉及Refught2和OkHttp时。

    public interface Interceptor {
      Response intercept(Chain chain) throws IOException;
    
      interface Chain {
        Request request();
    
        Response proceed(Request request) throws IOException;
    
        /**
         * Returns the connection the request will be executed on. This is only available in the chains
         * of network interceptors; for application interceptors this is always null.
         */
        @Nullable Connection connection();
      }
    }
    

    因此 Request 需要包含 User-Id 现在的问题是,我们如何让OkHttp从Jersey中获取这个用户Id?

    我认为没有一种简单的方法可以将东西注入RequestInterceptor 因为没问题。问题是Jersey是Java 1900-2000,其中改装和OkHttp类似于Java 2015+

    用户Id 在一个地方使用 RequestInterceptor parameter 在…内 intercept 该参数需要 用户Id 所以我们不必做像ThreadLocal或同步之类的讨厌的事情。

    更新:我做了一个简单的项目:

    https://github.com/andrewarrow/web-wash

    如果您查看此文件:

    https://github.com/andrewarrow/web-wash/blob/master/src/team/higher/web/resource/DashboardResource.kt

    目标是能够取代:

    userClient.getSomething(user_id)
    

    具有

    userClient.getSomething()
    

    并让userClient在线程中自动神奇地获取用户id 安全的方式。请记住:

    https://github.com/andrewarrow/web-wash/blob/master/src/team/higher/web/client/UserClient.kt

    @GET("user/test")
    fun getSomething(@Header("User-Id") id: String): String
    

    将使用@Header中的id,该id导致OKHttp和Refught2生成一个

    https://api.github.com/user/test

    1 回复  |  直到 6 年前
        1
  •  3
  •   Paul Samsotha    6 年前

    用户Id必须来自截取函数内的参数,而不是来自构造函数。该参数需要有用户Id,这样我们就不必做诸如ThreadLocal或同步之类的令人讨厌的事情。

    使用代理可以解决这个问题。使用Jersey,您可以为用户id创建一个小包装,然后让Jersey代理它。我们可以用一个 javax.inject.Provider 在拦截器中延迟检索用户。当我们这样做时,用户将被绑定到请求的上下文(这是有保证的,我们不需要担心管理我们自己的线程局部变量或任何事情)。

    public class UserIdInterceptor implements Interceptor {
    
        private final Provider<User> userProvider;
    
        UserIdInterceptor(Provider<User> userProvider) {
            this.userProvider = userProvider;
        }
    
        @Override
        public Response intercept(Chain chain) throws IOException {
    
            final User user = userProvider.get();
            if (user.isValid()) {
                return chain.proceed(chain.request().newBuilder()
                        .addHeader("User-Id", userProvider.get().getName())
                        .build());
            } else {
                return chain.proceed(chain.request());
            }
        }
    }
    

    Factory User 在请求范围中。这样,我们就可以为每个请求创建一个具有cookie的新用户。

    public class UserFactory implements Factory<User> {
    
        @Inject
        private Provider<ContainerRequest> request;
    
        @Override
        public User provide() {
            Cookie cookie = request.get().getCookies().get("User-Id");
            return cookie != null
                    ? new User(cookie.getValue())
                    : new User(null);
        }
    }
    

    我们要做的是为 Retrofit Provider<User> 当我们建造它时,把它传递给拦截器。

    public class RetrofitFactory implements Factory<Retrofit> {
    
        private final Retrofit retrofit;
    
        @Inject
        private RetrofitFactory(Provider<User> userProvider,
                                BaseUrlProvider urlProvider) {
    
            OkHttpClient client = new OkHttpClient.Builder()
                    .addInterceptor(new UserIdInterceptor(userProvider))
                    .build();
    
            this.retrofit = new Retrofit.Builder()
                    .baseUrl(urlProvider.baseUrl)
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(client)
                    .build();
        }
    
        @Override
        public Retrofit provide() {
            return this.retrofit;
        }
    }
    

    然后把它们绑在一起 AbstractBinder

    @Override
    public void configure() {
        bindFactory(RetrofitFactory.class)
                .to(Retrofit.class)
                .in(Singleton.class);
    
        bindFactory(UserFactory.class)
                .to(User.class)
                .in(RequestScoped.class)
                .proxy(true);
    
        bindFactory(ClientFactories.MessageClientFactory.class)
                .to(MessageClient.class);
    
        bind(new BaseUrlProvider(this.baseUrl))
                .to(BaseUrlProvider.class);
    }
    

    我在此制作了一个完整的演示 GitHub Repo