🔥

HonoをCGIとして使ってみる

2024/12/17に公開

この記事は、HonoAdventCalendar2024 17日目の記事です。

前置き

こんにちは。
今回はApacheで動くCGIとしてHonoを扱っていきたいと思います。
JSRでライブラリとして公開しています。
https://jsr.io/@taisan11/hono-cgi-adapter
リポジトリはこちらです。
https://github.com/taisan11/hono-cgi-adapter

CGIって?

CGIはApacheサーバー上で任意のプログラムを使用して、サーバーサイドの処理をするための仕組みです。

#!実行コマンド
ここにソースコードが来ます。

上記のように実行コマンドを置き設定で指定したディレクトリに置くことでそのファイルを実行できます。

Honoのアダプターって?

これは、Honoを様々な環境で動作させるための仕組みです。
例えばその環境に依存する処理(静的ファイルの取得)や、今回のようにWeb標準がサポートされてない場所でHonoを動かすときなどに使います。

今回の実装

上記の通り、CGIの値を中継していい感じにHonoにfetchして加工して返すといった処理をしています。
処理の内容は主に、Hono本体に内蔵されているアダプターのソースコードを参考に作成しました。

入力

https://github.com/taisan11/hono-cgi-adapter/blob/e98281da73b5f95e6f08bd63f87b0dce9444f271/cgi.ts#L39-L47
今回はDenoを使用しているので、Deno.env.toObject()で環境変数を取得、HTTPヘッダーにはHTTP_がついてるので、それをnew Header()に入れてる感じです。
そんな風にPOSTなどの場合にstdinからbodyを読み取って、
URLは今回はenvからアクセスしたCGIをルートのベースとしたパスと、自分のhostをURLで合体して使ってます。
それらをRequestにぶち込んで終わりです。

Honoにリクエストする。

Honoはすごく便利なため、Honoには直接fetchできるようになっています。
これもWeb標準のおかげですね。
https://github.com/taisan11/hono-cgi-adapter/blob/e98281da73b5f95e6f08bd63f87b0dce9444f271/cgi.ts#L70
なのでこんな風に普通にAPIリクエストするみたいに行えちゃえます。
さらに環境変数や、任意の関数も渡すこともできちゃうみたいです。
ここでは普通に環境変数を渡しています。

出力

出力は全てstdoutに出力します。
ステータスコードはStatus: ${response.status}といった形で出力して、他のヘッダーは普通にそのまま出力します。
最後に改行を挟んだのちbodyを出力して終了します。
https://github.com/taisan11/hono-cgi-adapter/blob/e98281da73b5f95e6f08bd63f87b0dce9444f271/cgi.ts#L80-L94
さらに、このコードを使うことで、ストリーミングも対応しています。
普通に、ストリーミング用のヘッダーがあるときに、responseからストリーミングを引っ張ってきてstdoutに出力し続けるだけです。

使い方

お待ちかね?の使い方です。

#!Denoへの完全パス --allow-env
import { Hono } from "npm:hono";
import { handle } from "jsr:@taisan11/hono-cgi-adapter";

const app = new Hono();

app.get('/', (c) => {return c.text('Hono!')});

handle(app);

をapacheのcgi-binディレクトリに置くだけで動きます。
deno.jsonを使ってたり、複数のファイルで動かしている場合は、いったんバンドルしてから配置してください。
因みに、CGIではリクエストごとに起動しているので、hono/quickというプリセットを使うといいと思います。

終わりに

同じようなコードで様々な環境で動かせるのはHonoの強みですよね。
Apacheを使わなきゃいけないけど、PHPやPerlが書けないときにお使いください。
あとDenoはシングルバイナリですので、レンタルウェブサーバーでも使いやすいかもしれません。

Discussion