在 OkHttp 库中使用拦截器

Working with Interceptors in OkHttp library

我需要生成带有所有请求参数的签名认证:

所以,我写了一个小的 SignatureInterceptor class:

public class SignatureInterceptor implements Interceptor {

    private String token;
    private String signature = "";
    private String method;
    private String query;

    public SignatureInterceptor() {
            this.token = "456456456456";
    }

    @Override
    public com.squareup.okhttp.Response intercept(Chain chain) throws IOException {
        Request originalRequest = chain.request();
        if (originalRequest.body() == null || originalRequest.header("Content-Encoding") != null) {
            return chain.proceed(originalRequest);
        }

        method = originalRequest.method();
        query = originalRequest.urlString();

        Request authenticatedRequest = originalRequest.newBuilder()
                .method(originalRequest.method(), authenticate(originalRequest.body()))
                .addHeader("signature", signature)
                .build();
        return chain.proceed(authenticatedRequest);
    }

    private RequestBody authenticate(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 {
                BufferedSink authSink = Okio.buffer(sink);
                body.writeTo(sink);

                String data = authSink.buffer().readUtf8();
                signature = generateSignature(method, query, data, token);
                authSink.close();
            }
        };
    }
}

问题是,对于拦截器,结果在执行期间流式传输,所以我无法在处理之前获取签名值。

那么,is-there 一种在 header 中插入在 writeTo() 流方法中生成的签名值的聪明方法?

已更新 根据@Jesse 回答的代码。

private class SignatureInterceptor implements Interceptor {

    @Override
    public com.squareup.okhttp.Response intercept(Chain chain) throws IOException {
        Request originalRequest = chain.request();
        String data = "";
        if (originalRequest.body() != null) {
            BufferedSink authSink = new Buffer();
            originalRequest.body().writeTo(authSink);
            data = authSink.buffer().readUtf8();
            authSink.close();
        }
        Request authenticatedRequest = originalRequest.newBuilder()
                .addHeader(HEADER_SIGNATURE, buildSignature(data))
                .build();
        return chain.proceed(authenticatedRequest);
    }
}

您不需要创建自己的 RequestBody class;仅当您转换 body.

时才有必要

writeTo 方法的内容移动到 intercept 中,这样您就可以在调用 proceed 之前计算签名。使用该签名添加 header.