nodeのrequestライブラリの`json`オプションの取り扱いについて調べてみた

2018/04/09

累計閲覧数 481 PV

TL;DR

つべこべいわず、該当コード見たほうが早い

コードを読んでもわからなかったら続きをどうぞ。

簡単に調べてみた

nodeのHTTP ClientであるrequestをPOST時に利用したとき、 json: trueのoptionがあるけど、bodyがjsonかされないっていう話を聞いたので、調べてみた。

どうやら、optionのjsonにBooleanではなく、直接Objectを渡したほうが早い。

実装コードから調べてみた

オプションのjsonをどうのように取り扱っているか

冒頭でも紹介したhttps://github.com/request/request/blob/master/request.js#L1278-L1313である。

いろいろぶっ飛ばして、

Request.prototype.json = function (val) {
  var self = this

  // 中略

  self._json = true
  if (typeof val === 'boolean') {
    // jsonオプションの値がbooleanの場合
    if (self.body !== undefined) {
      // bodyがundefinedでなけれあば
      if (!/^application\/x-www-form-urlencoded\b/.test(self.getHeader('content-type'))) {
        // content-typeが application/x-www-form-urlencoded とマッチした倍、
        // https://github.com/request/request/blob/master/lib/helpers.js#L20-L28
        self.body = safeStringify(self.body, self._jsonReplacer)
      } else {
        // rfc3986でエンコード
        // https://github.com/request/request/blob/master/lib/querystring.js#L42-L46
        self.body = self._qs.rfc3986(self.body)
      }
      if (!self.hasHeader('content-type')) {
        // content-typeが指定されていなければ、application/jsonに指定
        self.setHeader('content-type', 'application/json')
      }
    }
} else {
    // jsonがbooleanでないとき 
    // bodyに入れ直していますね。
    self.body = safeStringify(val, self._jsonReplacer)
    if (!self.hasHeader('content-type')) {
      // content-typeが指定されていなければ、application/jsonに指定
      self.setHeader('content-type', 'application/json')
    }
  }

  return self
}

これで謎は解けました。 rfc3986が出てきたのですが、別の章で紹介。

もっと詳しく見てみる

渋川さんの記事が大変参考になります。 読んでいた当時はよくわからなかったのですが、今となっては噛み締めて読めますね。。。 RFC大事。

RFC3986に厳格に対応したライブラリ

RFC3986関連