LoginSignup
1
2

More than 3 years have passed since last update.

MessagePackのバイト列をクエリパラメータとしてHTTPリクエストを送る[JS]

Last updated at Posted at 2018-12-20

MessagePackでエンコードしたバイト列をaxiosでクエリパラメータに含めて送りたかったのですが、ちょっとハマったので書き留めておきます。

環境

バージョン
node 10.12.0
axios 0.18.0
msgpack-lite 0.1.26

目標

const data = [{
    bar: 'bar',
    foo: 'foo',
}]

このようなObjectを送ることを考える。

https://msgpack.org/ で確認してみるとこのObjectはMessagePackによって以下のようなバイト列になる。

91 82 a3 62 61 72 a3 62 61 72 a3 66 6f 6f a3 66 6f 6f

ということはクエリパラメータはこんな感じになってくれると嬉しい。

...?data=%91%82%A3bar%A3bar%A3foo%A3foo

これはUTF-8でエンコードできるバイトはエンコードし、できないバイトは%を頭につけて16進数として出力するパーセント・エンコーディングです。

課題

まず書いたコードはこんな感じ。

const data = {
    bar: 'bar',
    foo: 'foo',
}

const buf = msgpack.encode(data)

axios.get(
    endpoint,
    { params: { data: buf } },
)

送られたクエリパラメータ

...?data=%7B%22type%22:%22Buffer%22,%22data%22:[130,163,98,97,114,163,98,97,114,163,102,111,111,163,102,111,111]%7D

BufferのObjectがそのままエンコードされてるっぽい…。

ということで以下のようにBufferをStringに修正してみる。


const buf = msgpack.encode(data).toString()

axios.get(
    endpoint,
    { params: { data: buf } },
)

送られたクエリパラメータ

...?data=%EF%BF%BD%EF%BF%BDbar%EF%BF%BDbar%EF%BF%BDfoo%EF%BF%BDfoo

ん?UTF-8でエンコードできない部分がなんかすごいことになってる。

調べてみるとエンコード失敗した時の文字列をさらにエンコードしようとしてこうなってしまうらしい…。

(参照)

解決策

これではリクエストを受け取った側でmsgpackとしてデコードできないのでどうしたものかと調べてみると、axiosではクエリパラメータのシリアライザをカスタマイズできるらしい。

実装したコードはこんな感じ。

const buf = msgpack.encode(data);

axios
  .get(
    endpoint,
    {
      params: { data: buf },
      paramsSerializer: (params) => {  // シリアライザをカスタマイズ
        let result = '';
        for(let k of Object.keys(params)) {
          if (result !== "") {
            result += "&";
          }
          if (params[k] instanceof Buffer) {  // Bufferだけエンコードが失敗しないようにする
            let encodedData = '';
            for (let value of params[k].values()) {
              encodedData += '%' + value.toString(16);
            }
            result += k + "=" + encodedData;
          } else {
            result += k + "=" + encodeURI(params[k]);  // Buffer以外は普通にエンコード
          }
        }
        return result;
      },
  },
);

paramsSerializerを指定することによってシリアライザをカスタマイズできました。
内容としてはBufferに対してのみ単純なパーセント・エンコーディングを適用するようにしたものです。

まとめ

axiosは簡単なことは簡単にできながら、カスタマイズも細かくできるのがいいなと思いました。
他にいい方法があればコメントください!

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2