【TypeScript】JSから投げるhttpリクエストのエラーコードHPE_INVALID_CONSTANTを出力
こんばんは葛の葉です。
URLを集めている業務がありまして、httpリクエストを投げてステータスコードを集めているのですが、そのときに時々に発生したエラーコード「HPE_INVALID_CONSTANT」に随分悩まされました。
そのときにこのツイートを見かけてクララが立ちました。
TIL: Node.js in *some* instances throws a HPE_INVALID_CONSTANT if the Content-Length header in a http request has the wrong value.
— Erwin Wessels (@htwj) 2019年5月30日
つまり、HttpヘッダーのContent-Length
の値が実際と違う場合にHPE_INVALID_CONSTANT
が発生するようです。
Version
{ "node": "12.13.1", "request": "2.88.2", "request-promise": "4.2.5" }
今回もお世話になっているhttpモジュールとRequest-Promiseモジュールを使います。
再現してみよう
以下にソースを書きます。
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モジュールなんかを使うと良いと思います。
} 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データは。。。。頑張って加工して使ってみてくれ😥