http2.createServer()のhandlerで、HTTP/1のサーバーを立てる (Node.js/TypeScript)
#Node.js #TypeScript #HTTP/2 #HTTP/1 #制作物
GitHubリポジトリ
https://gh-card.dev/repos/nwtgck/http2-http1-server-node.svg https://github.com/nwtgck/http2-http1-server-node
既存の問題を整理
TypeScriptの型定義だと、http.createServer()とhttp2.createServer()の引数の型が違う(執筆時)。
code:ts
// http
function createServer(options: ServerOptions, handler?: (req: IncomingMessage, res: ServerResponse) => void): Server;
code:ts
// http2
export function createServer(options: ServerOptions, handler?: (request: Http2ServerRequest, response: Http2ServerResponse) => void): Http2Server;
handlerの型が違うため、HTTPSを使わないHTTP/2とHTTP/1に両方対応するときには、2つの異なる実装のhandlerを実装する必要があるはず。思考: DefinitelyTypedで、http.createServer()とhttp2.createServer()のハンドラーの型が合わなくて考えていることでどうすれば型定義を共通化できそうか考えた軌跡が少し残っている。
http2.createSecureServer()だとHTTP/1もHTTP/2も両方とも対応してくれる(ただしSSL/TLSが必要になる)。
http2.createServer()だと、HTTP/2のみの対応で、HTTP/1の通信は受け付けない。HTTP/1を付けつけないことはNode.js本体でテストされている:Node.jsのhttp2.createServer()がHTTP/1のリクエストを受け付けない仕様のテストコードの場所
やりたいことから、妥協可能な解決策導く
結局やりたいことは、以下のことだと思う。
HTTPSとHTTPの対応と、
HTTP/2の対応と、
HTTP/1クライントとの互換性を保つことと、
handlerの実装は一つにする
そのため、必然的にHTTPSとHTTP/2の対応のため、「http2.createSecureServer()」が使われるはず。
だから、そのメソッドのhandlerの型にマッチしたhandlerは必ず作るはず。そこで、HTTP(non-TLS)のサーバーはHTTP/1だけに対応するという少し妥協した解決策をとる。HTTP/2 over non-TLSを対応しない妥当性は、多くのブラウザがHTTP/2はHTTPSを使っていないとサポートしないようになっているから。
ということで、handlerの型が(request: Http2ServerRequest, response: Http2ServerResponse) => voidでも、HTTP(non-TLS)サーバーを作りたくなった。それを実現するための方法の一つが上記のリポジトリがやりたかったこt。
使い方
以下みたいにhttp2用のhandlerを使ってHTTP/1サーバーを立てることができる。
code:ts
import { createServer } from "http2-http1-server";
import * as http2 from "http2";
import { readFileSync } from "fs";
const cert = readFileSync('./ssl_certs/server.crt');
const key = readFileSync('./ssl_certs/server.key');
const handler = (req: http2.Http2ServerRequest, res: http2.Http2ServerResponse) => {
res.end("hello from server!");
};
// ここ大事! 同じハンドラーでHTTP/2 over HTTPSと普通のHTTP/1 over non-TLS作れる!
const server = createServer({}, handler);
const secureServer = http2.createSecureServer({cert, key}, handler);
server.listen(8080);
secureServer.listen(8443);
まとめ
http2-http1-serverはHTTP/1サーバー
http2-http1-serverを作るときはhttp2のhandlerを渡せる
http.createServer()とhttp2.createServer()が共通のインターフェイスを持ってくれるとこのリポジトリが不要になってハッピー