6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ateam LifeDesignAdvent Calendar 2023

Day 17

SvelteKit の handleFetch って何が嬉しいの?

Last updated at Posted at 2023-12-16

はじめに

SvelteKit には handleFetch というものがあり、翻訳サイトには以下のように書いてあります。

handleFetch
この関数は、サーバー上で (またはプリレンダリング中に) 実行される load 関数や action 関数の中で発生する fetch リクエストを変更 (または置換) することできます。

例えば、ユーザーがクライアントサイドでそれぞれのページに移動する際に、load 関数で https://api.yourapp.com のようなパブリックな URL にリクエストを行うかもしれませんが、SSR の場合には (パブリックなインターネットとの間にあるプロキシやロードバランサーをバイパスして) API を直接呼ぶほうが理にかなっているでしょう。

なぜ、SSR の場合には API を直接呼ぶほうが理にかなっているのでしょうか?

ざっくり概要図

ざっくりと handleFetch がない場合とある場合との比較をしてみます。

SvelteKitのhandleFetchを使うとリクエストが外部ネットワークを通らなくなるので低遅延

handleFetch を使うとリクエストがVPC内で完結する

  • メリット
    • 低遅延: VPC 内部通信なので、通常は外部ネットワークよりも低い遅延が期待できる
    • セキュリティ向上: プライベートネットワーク内で通信するので外部から傍受されない
  • デメリット
    • API が外部ネットワーク経由と VPC 内経由の両方になると、不具合が発生した際に考慮すべき事項が増える

handleFetch の書き方

SvelteKitはhandleFetchを使ってAPIのURLを置換してから内部ロードバランサにリクエストを送っている

handleFetch がある場合に、SvelteKit でURLを置換しています。これは、公式リファレンスの書き方を参考に書くと以下のようになります。

src/hooks.server.js
/** @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 を取り出し、新しいリクエストにセットする必要があります。

src/hooks.server.js
/** @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 でアプリケーションを構築するとき、この記事で書いたネットワーク・リクエストの流れを抑えておくと、どんな設定が必要か気づくきっかけになるのかなと思います:relaxed:

参考

SvelteKit日本語翻訳サイト

6
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?