2014年4月7日月曜日

GZIP圧縮に対応したHTTPクライアントを作る

前回の記事で予告したとおり、今回はC#でGZIP圧縮に対応したHTTPクライアントを作ります。
ポイントは3つあります。

  1. GZipStreamを使って入力データを圧縮する
  2. HttpClientHandlerのAutomaticDecompressionプロパティを設定する
  3. HTTPリクエストヘッダのContent-Encodingをgzipに設定する

GZipStreamを使って入力データを圧縮する
圧縮用にMemoryStreamをインスタンス化し、GZipStreamでラップします。
usingをネストしているのはGZipStreamをCloseするタイミングで圧縮が実行されるからです。
byte[] data = null;

using (var memory = new MemoryStream()) {
  using (var gzip = new GZipStream(memory, CompressionMode.Compress)) {
    int input = 0;
    byte[] buffer = new byte[1];

    while (-1 != (input = Console.Read())) {
      buffer[0] = Convert.ToByte(input);
      gzip.Write(buffer, 0, buffer.Length);
    }
  }
  data = memory.ToArray();
}

HttpClientHandlerのAutomaticDecompressionプロパティを設定する
リクエストボディの圧縮は実装する必要がありますが、レスポンスの解凍は.NET Frameworkが対応しています。
var clientHandler = new HttpClientHandler();
clientHandler.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;

HTTPリクエストヘッダのContent-Encodingをgzipに設定する
コンテンツがgzip圧縮されていることを示すため、Content-Encodingをgzipに設定します。
using(var client = new HttpClient(clientHandler))
using(var content = new ByteArrayContent(data))
{
  content.Headers.ContentEncoding.Add("gzip");
  using(var message = client.PostAsync(url, content).Result)
  {
    Console.WriteLine(message.Content.ReadAsStringAsync().Result);
  }
}

一般的に、HTTPリクエストが圧縮を必要とするほど大きくなることはありません。
全ての画面データを毎回やりとりするような設計であれば、効果があるかもしれません。

プログラム全体を以下に記載します。

// csc /reference:System.Net.Http.dll GZipHttpClient.cs

namespace gziphttpclient {

  using System;
  using System.IO;
  using System.IO.Compression;
  using System.Net;
  using System.Net.Http;
  
  public class GZipHttpClient {
    public static void Main(string[] args) {
      const string url = "http://localhost:8080/echo";
      
      byte[] data = null;
      
      using (var memory = new MemoryStream()) {
        using (var gzip = new GZipStream(memory, CompressionMode.Compress)) {
          int input = 0;
          byte[] buffer = new byte[1];
          
          while (-1 != (input = Console.Read())) {
            buffer[0] = Convert.ToByte(input);
            gzip.Write(buffer, 0, buffer.Length);
          }
        }
        data = memory.ToArray();
      }

      var clientHandler = new HttpClientHandler();
      clientHandler.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
      
      using(var client = new HttpClient(clientHandler))
      using(var content = new ByteArrayContent(data))
      {
        content.Headers.ContentEncoding.Add("gzip");
        using(var message = client.PostAsync(url, content).Result)
        {
          Console.WriteLine(message.Content.ReadAsStringAsync().Result);
        }
      }
    }
  }
}

参考
GZipStream Class
HttpClientHandler Class

関連
FilterでHTTP通信のGZIP圧縮に対応する

0 件のコメント:

コメントを投稿