5 votes

Retrofit : comment analyser une réponse GZIP sans l'en-tête Content-Encoding : gzip ?

J'essaie de traiter une réponse de serveur qui est GZIPée. La réponse est accompagnée d'un en-tête

Content-Type: application/x-gzip

mais n'a pas d'en-tête

Content-Encoding: gzip

Si j'ajoute cet en-tête en utilisant un proxy, la réponse est analysée sans problème. Je n'ai aucun contrôle sur le serveur, je ne peux donc pas ajouter l'en-tête.

Puis-je forcer Retrofit à le traiter comme un contenu GZIP ? Existe-t-il un meilleur moyen ? L'URL du serveur est : http://crowdtorch.cms.s3.amazonaws.com/4474/Updates/update-1.xml

7voto

itsymbal Points 98

J'ai trouvé la solution. L'idée est d'ajouter un intercepteur personnalisé qui va prendre la réponse non encore décompressée, et la décompresser "manuellement" - faire la même chose que OkHttp ferait automatiquement en se basant sur l'en-tête Content-Encoding, mais sans exiger cet en-tête.

est comme dis :

    OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
            .addInterceptor(new UnzippingInterceptor());
    OkHttpClient client = clientBuilder.build();

Et l'Interceptor est comme dis :

private class UnzippingInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Response response = chain.proceed(chain.request());
        return unzip(response);
    }
}

Et la fonction de dézippage est comme dis :

    // copied from okhttp3.internal.http.HttpEngine (because is private)
private Response unzip(final Response response) throws IOException {

    if (response.body() == null) {
        return response;
    }

    GzipSource responseBody = new GzipSource(response.body().source());
    Headers strippedHeaders = response.headers().newBuilder()
            .removeAll("Content-Encoding")
            .removeAll("Content-Length")
            .build();
    return response.newBuilder()
            .headers(strippedHeaders)
            .body(new RealResponseBody(strippedHeaders, Okio.buffer(responseBody)))
            .build();
}

1voto

Abhijit Sarkar Points 206

Il existe un meilleur moyen que de réinventer la roue. Il suffit d'ajouter le Content-Encoding l'entête vous-même.

.addNetworkInterceptor((Interceptor.Chain chain) -> {
    Request req = chain.request();
    Headers.Builder headersBuilder = req.headers().newBuilder();

    String credential = Credentials.basic(...);
    headersBuilder.set("Authorization", credential);

    Response res = chain.proceed(req.newBuilder().headers(headersBuilder.build()).build());

    return res.newBuilder()
        .header("Content-Encoding", "gzip")
        .header("Content-Type", ""application/json")
        .build();
})

En fait, votre code est un exemple classique des méfaits de l'utilisation de code interne (comme com.sun du JDK). RealResponseBody n'a plus ce constructeur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X