はじめに
ReactからHonoで作ったAPIを呼び出すときに、CORSの設定が必要になりました。
今回のアプリでは、ReactとHono APIを別々のポートで動かしています。
React: http://localhost:5173
Hono API: http://localhost:3000
どちらもlocalhostなので、そのまま通信できそうに感じましたが、実際にはポート番号が違うため、ブラウザから見ると別のオリジンとして扱われます。
そのため、ReactからHono APIを呼び出すには、API側でCORSの設定が必要でした。
この記事では、CORSとは何か、なぜlocalhost同士でもCORSが必要になるのか、そしてHonoでどのようにCORSを設定したのかを整理します。
CORSとは
CORSは、Cross-Origin Resource Sharingの略です。
MDNでは、CORSについて次のように説明されています。
CORS is an HTTP-header based mechanism that allows a server to indicate any origins other than its own from which a browser should permit loading resources.
引用元: MDN - Cross-Origin Resource Sharing (CORS)
簡単に言うと、CORSは「別のオリジンからのリクエストを許可するかどうか」をサーバーがブラウザに伝えるための仕組みです。
ブラウザには、セキュリティのために同じオリジン以外へのリクエストを制限する仕組みがあります。
そのため、フロントエンドから別のオリジンにあるAPIを呼び出す場合、APIサーバー側で「このオリジンからのリクエストは許可します」と伝える必要があります。
CORSの設定がないと、API自体はレスポンスを返していても、ブラウザがそのレスポンスをフロントエンドのJavaScriptから使わせてくれないことがあります。
つまりCORSは、フロントエンドとAPIが別のオリジンにあるときに、ブラウザ上で安全に通信するための仕組みです。
今回の構成
今回のアプリでは、ReactとHono APIを別々のポートで動かしていました。
React: http://localhost:5173
Hono API: http://localhost:3000
どちらもlocalhostなので、同じ場所(PC内)で動いているように感じますが、ブラウザではオリジンを次の3つの組み合わせで判断します。
スキーム: http
ホスト: localhost
ポート: 5173 / 3000
今回の場合、スキームとホストは同じですが、ポート番号が違います。
http://localhost:5173
http://localhost:3000
そのため、この2つは別のオリジンとして扱われます。
ReactからHono APIを呼び出す場合、ブラウザから見ると別オリジンへのリクエストになります。
そのため、API側でCORSを設定して、http://localhost:5173からのリクエストを許可する必要がありました。
HonoでCORSを設定する
Honoでは、CORS用のミドルウェアが用意されています。
今回のTODOアプリでは、hono/corsからcorsをimportして使いました。
import { cors } from "hono/cors";
実際の設定は次のように書きました。
app.use(
cors({
origin: "http://localhost:5173",
}),
);
この設定では、http://localhost:5173からのリクエストを許可しています。
今回の構成では、Reactがhttp://localhost:5173で動いていて、Hono APIがhttp://localhost:3000で動いています。
そのため、ReactからAPIを呼び出せるようにするために、API側でReactのオリジンを許可しました。
CORSの設定は、フロントエンド側ではなくAPIサーバー側で行います。
HonoではミドルウェアとしてCORSを設定できるので、少ないコードで対応できました。
なぜAPI側で設定するのか
CORSは、フロントエンド側で「このAPIを呼び出してもよい」と決める仕組みではなく、APIサーバー側が「このオリジンからのリクエストは許可する」とブラウザに伝えるための仕組みです。
もしフロントエンド側で自由に許可できてしまうと、悪意のあるサイトでも勝手に「許可されたこと」にできてしまいます。
そのため、どのオリジンを許可するかは、APIを提供しているサーバー側が決める必要があります。
学んだこと
今回CORSについて調べて、まずlocalhost同士でもCORSが必要になる場合があることを学びました。
また、CORSはフロントエンド側で許可するものではなく、APIサーバー側で設定するものだとわかりました。
フロントエンド側で自由に許可できてしまうと、悪意のあるサイトでも勝手にAPIのレスポンスを利用できてしまいます。
そのため、APIを提供しているサーバー側が「どのオリジンからのリクエストを許可するか」を決める必要があります。
Honoでは、hono/corsのミドルウェアを使うことで、少ないコードでCORSを設定できました。
app.use(
cors({
origin: "http://localhost:5173",
}),
);
この設定によって、Hono API側でhttp://localhost:5173からのリクエストを許可できました。
CORSは最初少しわかりにくかったですが、今回の実装を通して、フロントエンドとAPIを別のオリジンで動かすときに必要になる仕組みだと理解できました。