Kuzunoha-NEのブログ

プログラミングなどの勉強をしてます

【TypeScript】JSから投げるhttpリクエストのエラーコードHPE_INVALID_CONSTANTを出力

こんばんは葛の葉です。

URLを集めている業務がありまして、httpリクエストを投げてステータスコードを集めているのですが、そのときに時々に発生したエラーコード「HPE_INVALID_CONSTANT」に随分悩まされました。

そのときにこのツイートを見かけてクララが立ちました。

つまり、HttpヘッダーのContent-Lengthの値が実際と違う場合にHPE_INVALID_CONSTANTが発生するようです。

Version

{
  "node": "12.13.1",
  "request": "2.88.2",
  "request-promise": "4.2.5"
}

今回もお世話になっているhttpモジュールとRequest-Promiseモジュールを使います。

nodejs.org

github.com

再現してみよう

以下にソースを書きます。

import http from "http";

import * as rp from "request-promise";

// Initilaize
const port: number = 9991;
const host: string = `http://localhost:${port}/`;

// Create Http Server
const server = http.createServer((_, response) => {
  // Content-Lengthが1byteと宣言する。
  response.setHeader("Content-Length", 1);
  // 実際のデータは3byteでContent-Lengthとは矛盾する。
  response.write("aaa");
  response.end();
});

// Http Server Run
server.listen(port, () => {
  console.log(`listen ${host}`);
});

(async () => {
  try {
    // Http Get Request to Http Server ここでParse Errorが発生しCatchされる。
    const hoge = await rp.get(host);
    // Print Http Response
    console.log(hoge);
  } catch (e) {
    // Print Error Code
    console.log(e.error.code); // HPE_INVALID_CONSTANT
    //console.log(e.error.rawPacket);
    //console.log(Buffer.from(e.error.rawPacket).toString());
  } finally {
    server.close();
  }
})();

const hoge = await rp.get(host);のタイミングでHttpRequestを上記の作成したHttpサーバーに投げています。そのタイミングでParseErrorというエラーが発生します。そのエラーをキャッチした際に表示されるエラーコードがHPE_INVALID_CONSTANTになります。

ブラウザで見るとちゃんと表示されてたりするので、一見すると問題なさそうなページに対し、プログラムからHttpRequestを投げるとHPE_INVALID_CONSTANTというエラーコードが出力されて面食らうというのが調べるに至った経緯というわけになります。

元データはrawPacketへ

キャッチしたエラーにrawPacketが入っている場合があります。バイナリデータになっているのでStringに変換してあげると色々と使えるかもしれないです。

  } catch (e) {
    console.log(Buffer.from(e.error.rawPacket).toString());
  } finally {
    server.close();
  }
HTTP/1.1 200 OK
Content-Length: 1
Date: Fri, 13 Mar 2020 16:47:19 GMT
Connection: close

aaa

ヘッダーに関してはこのままだと使いにくいので、色々と加工してくれるhttp-headersモジュールなんかを使うと良いと思います。

www.npmjs.com

  } catch (e) {
    const packet = Buffer.from(e.error.rawPacket).toString()
    console.log(parse(packet))
{
  version: { major: 1, minor: 1 },
  statusCode: 200,
  statusMessage: 'OK',
  headers: {
    'content-length': '1',
    date: 'Fri, 13 Mar 2020 16:53:31 GMT',
    connection: 'close'
  }
}

Bodyデータは。。。。頑張って加工して使ってみてくれ😥