はじめに
SvelteKit には handleFetch
というものがあり、翻訳サイトには以下のように書いてあります。
handleFetch
この関数は、サーバー上で (またはプリレンダリング中に) 実行されるload
関数やaction
関数の中で発生するfetch
リクエストを変更 (または置換) することできます。例えば、ユーザーがクライアントサイドでそれぞれのページに移動する際に、
load
関数でhttps://api.yourapp.com
のようなパブリックな URL にリクエストを行うかもしれませんが、SSR の場合には (パブリックなインターネットとの間にあるプロキシやロードバランサーをバイパスして) API を直接呼ぶほうが理にかなっているでしょう。
なぜ、SSR の場合には API を直接呼ぶほうが理にかなっているのでしょうか?
ざっくり概要図
ざっくりと handleFetch
がない場合とある場合との比較をしてみます。
handleFetch を使うとリクエストがVPC内で完結する
- メリット
- 低遅延: VPC 内部通信なので、通常は外部ネットワークよりも低い遅延が期待できる
- セキュリティ向上: プライベートネットワーク内で通信するので外部から傍受されない
- デメリット
- API が外部ネットワーク経由と VPC 内経由の両方になると、不具合が発生した際に考慮すべき事項が増える
handleFetch の書き方
handleFetch がある場合に、SvelteKit でURLを置換しています。これは、公式リファレンスの書き方を参考に書くと以下のようになります。
/** @type {import('@sveltejs/kit').HandleFetch} */
export async function handleFetch({ request, fetch }) {
if (request.url.startsWith('https://api.yourapp.com/')) {
request = new Request(
request.url.replace(
'https://api.yourapp.com/',
'https://local.yourapp.com/'),
request
);
}
return fetch(request);
}
local.yourapp.com
というドメインは、外部に公開されていないプライベートなDNSを想定していて、その先に内部ロードバランサーのアドレスが設定されています。
クレデンシャル(認証情報)が維持できない場合
handleFetch で URL を書き換える場合に注意しないといけないのは、認証情報の扱いです。
上述の例では、yourapp.com
ドメインでホストした SvelteKit から、local.yourapp.com
サブドメインへのリクエストでは認証情報を引き継ぎます。しかし、もし SvelteKit を www.yourapp.com
ドメインでホストしていた場合は認証情報を引き継ぎません。また、local.yourapp.com
ではなく api.hoge
のように、異なるドメインでも同様です。
これを解決するには、手動で元のリクエストから cookie を取り出し、新しいリクエストにセットする必要があります。
/** @type {import('@sveltejs/kit').HandleFetch} */
export async function handleFetch({ event, request, fetch }) {
...
+ if (request.url.startsWith('https://api.yourapp.com/')) {
+ request.headers.set('cookie', event.request.headers.get('cookie'));
+ }
return fetch(request);
}
おわりに
SSR で構築していると、どうしてもユーザーごとに異なるコンテンツを返す必要がでてきますし、マイページであれば認証してからでないと表示できません。そうした場合、サーバーサイドで認証 API を実行する必要があります。
SvelteKit でアプリケーションを構築するとき、この記事で書いたネットワーク・リクエストの流れを抑えておくと、どんな設定が必要か気づくきっかけになるのかなと思います
参考
SvelteKit日本語翻訳サイト