http2.createServer()のhandlerで、HTTP/1のサーバーを立てる (Node.js/TypeScript)
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;
http2.createSecureServer()だとHTTP/1もHTTP/2も両方とも対応してくれる(ただしSSL/TLSが必要になる)。
やりたいことから、妥協可能な解決策導く
結局やりたいことは、以下のことだと思う。
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()が共通のインターフェイスを持ってくれるとこのリポジトリが不要になってハッピー