1. ホーム
  2. java

HttpClientがGZIP形式でない場合の対処法

2022-02-09 13:40:46
<パス

HttpClientで画像を取得する過程で、以下のようなエラーが表示されました。

Exception in thread "main" java.util.zip.ZipException: Not in GZIP format
    GZIPInputStream.readHeader(GZIPInputStream.java:165)
    at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:79)
    at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:91)
    at org.apache.http.client.protocol.ResponseContentEncoding$1.create(ResponseContentEncoding.java:68)
    at org.apache.http.client.entity.LazyDecompressingInputStream.initWrapper(LazyDecompressingInputStream.java:51)
    at org.apache.http.client.entity.LazyDecompressingInputStream.read(LazyDecompressingInputStream.java:63)
    at com.didichuxing.upload.TestUploadFile.main(TestUploadFile.java:53)

例外スタックのソースコードを読むと、HTTPリクエストヘッダに "Content-Encoding: "compress,gzip"" が含まれており、これを元にHttpClientが返ってきたInputStreamを "Content-Encoding" に従ってラップしており、そのソースコードは以下の通りであることがわかりました。

// excerpt, see org.apache.http.client.protocol.ResponseContentEncoding for details
final Header ceheader = entity.getContentEncoding();
// ......
// with ignore
final InputStreamFactory decoderFactory = decoderRegistry.lookup(codecname);

つまり、2つの関連するソリューションがあるわけです。

1.クライアント側の解決策

HTTPリクエストを診断するには、ヘッダー情報がポイントになります。

"Content-Encoding", "compress,gzip"

しかし残念ながら、クライアントにはHTTPヘッダを変更する機能はありません( 読み取りアクセスのみ ) のため、HttpClientがGZIPで処理する前に、以下のようにしてストリームを取得する必要があります。

CloseableHttpClient httpclient = HttpClients.custom().addInterceptorFirst(new HttpResponseInterceptor() {

    @Override
    public void process(HttpResponse response, HttpContext context) throws HttpException, IOException {
        HttpEntity resEntity = response.getEntity();
        // consume the InputStream here
        BufferedInputStream ins = new BufferedInputStream(resEntity.getContent());
        FileOutputStream fos = new FileOutputStream("water1.png");
        byte[] buffer = new byte[4096];
        int len = 0;
        while((len = ins.read(buffer)) > -1) {
            fos.write(buffer, 0, len);
        }
        fos.close();
    }
}).build();

要約すると、このエラーの根本原因のほとんどは、以下のようにHttpClientのデフォルトの構成に起因しています。

// Generic role, but not applicable in all cases
CloseableHttpClient httpclient = HttpClients.createDefault();

2. サーバーサイドソリューション

サーバーサイドでの解決方法は簡単ですが、唯一の問題は、コードを修正するために、以下のようにサーバーサイドのアクセス権が必要なことです。

// Don't enable this mode
// response.setHeader("Content-Encoding", "compress,gzip");
// change to normal stream mode
response.setHeader("Content-Encoding", "application/octet-stream");

ふと、冗談が頭に浮かぶ。

<ブロッククオート

専門家は、中国の神爆がいかに強力か、米帝のホワイトハウスの上を軍用機が飛ぶだけで、白地に吹き飛ぶと自慢しているのだ。そこで問題なのは、軍用機がどうやってどこに行くのか、ということだ。

もうひとつの方法は、サーバー側で実際にGZipモードをサポートすることです。 GZIP圧縮を有効にするためのTOMCATのセットアップ [私は何度かこれを試しましたが、特に画像サポートではうまくいかないようです]。

3. その他

JAVA HttpClientを使用したファイルの自動アップロード、クロールの詳細は以下の通りです。
1. ファイルアップロードのためのHTTPクライアントアプローチ
2. HTTPクライアントからファイルをアップロードするための改良されたアプローチ

4. 参考文献

  1. HttpClientチュートリアル ;
  2. HttpClientの例