使用 Retrofit/OkHttp 时修改 POST 请求正文

Modifying POST request Body when using Retrofit/OkHttp

到目前为止,我一直在使用 OkHttp 进行网络请求,但现在我想使用 Retrofit (v2)。 我正在与之通信的服务器需要 AuthToken 作为 Url(GET 请求)或内部 Body(POST 请求)的一部分。 我还需要将请求创建与执行分开,顺便说一句,这是 Retrofit 非常好的功能,即我可以稍后传递 Call 对象和 execute/enqueue 它。

困难的部分是创建请求时 AuthToken 可能不可用,我需要在执行之前修改它。到目前为止,我一直在创建时添加一个虚拟 authToken 并在执行前替换它。 这对于 GET 请求来说非常简单,因为我可以将拦截器添加到 OkHttpClient 中以修改请求 Url 但是修改 POST 请求的主体是我正在努力的事情。

那么,Retrofit/OkHttp是否支持这个用例?

一些不起作用的示例代码几乎可以解决问题(尝试始终在可用时添加 authToken,结果是:java.lang.IllegalStateException:无法在没有分块编码或已知内容长度的情况下流式传输请求正文!

client.networkInterceptors().add(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();

            if (request.body() == null) {
                return chain.proceed(request);
            }

            Request authorizedRequest = request.newBuilder()
                    .method(request.method(), replaceDummyAuth(request.body()))
                    .build();
            return chain.proceed(authorizedRequest);
        }

        private RequestBody replaceDummyAuth(final RequestBody body) {
            return new RequestBody() {
                @Override
                public MediaType contentType() {
                    return body.contentType();
                }

                @Override
                public long contentLength() throws IOException {
                    return -1;
                }

                @Override
                public void writeTo(BufferedSink sink) throws IOException {
                    ParametersMap map = new ParametersMap();

                    BufferedSink authSink = Okio.buffer(sink);
                    body.writeTo(authSink);

                    String authToken = SessionManager.getAuthToken();
                    if(StringUtils.hasText(authToken)) {
                        map.put("authToken", authToken);
                        String paramString = map.getParameterString();
                        authSink.write(paramString.getBytes("UTF-8"));
                    }
                    authSink.close();
                }
            };
        }
    });

目前不支持我要求的用例,因此我为 Retrofit 创建了关于它的新问题,请参阅 Argument pre-processor, deserialized post-processor #816