Orbit

エッジ機能

Edge functions are small JavaScript handlers that run on Kapsule's edge network before a request reaches your project, so you can do redirects, header injection, A/B routing and bot filtering…

エッジ関数は Kapsule のエッジネットワーク上で実行される小さな JavaScript ハンドラーで、リクエストがプロジェクトに到達する前に実行されます。これにより、アプリへのラウンドトリップなしにリダイレクト、ヘッダー注入、A/B ルーティング、ボットフィルタリングを実行できます。このガイドでは、エッジ関数の書き方、受け入れられるエントリーポイント形式、パスマッチング、複数の関数の相互作用、デプロイ、および関数が例外をスローした場合の動作について説明します。

どこに配置されるか

Orbit でプロジェクトを開き、Edge functions タブをクリックします。すべての関数はプロジェクトに属し、ステータスバッジ LIVEPAUSEDNOT DEPLOYEDDEPLOY FAILED 付きでリストされます。

Orbit プロジェクトの Edge functions タブ

関数の作成

  1. New function をクリックします。
  2. Name に入力します(最大 120 文字)。
  3. Path pattern に入力します。この関数が実行される URL パターンです。
  4. Trigger を選択します。Request(オリジン前)、Response(オリジン後)、または Both。
  5. Environment scope を選択します。All environments、Production only、または Preview only。
  6. Function body にハンドラーを書き込みます。
  7. Save をクリックして、Deploy to edge をクリックします。

request オブジェクトは常にスコープ内にあり、ソースは 64 KB に制限されます。

ハンドラーの書き方

エッジでリクエストに答えるために Response を返します。何も返さないか undefined を返すと、リクエストはプロジェクトにそのまま渡されます。

export default {
  async fetch(request) {
    const url = new URL(request.url)

    // Redirect /old to /new
    if (url.pathname === '/old') {
      return new Response(null, {
        status: 301,
        headers: { Location: '/new' },
      })
    }

    // Returning nothing passes through to the origin
  },
}

名前付き関数形式も機能します:

export default async function handler(request) {
  // Add a security header to every response
  const response = await fetch(request)
  const headers = new Headers(response.headers)
  headers.set('X-Frame-Options', 'DENY')
  return new Response(response.body, { status: response.status, headers })
}

サポートされているエントリーポイント形式

形式
fetch メソッドを持つオブジェクトexport default { async fetch(request) { ... } }
アロー fetch プロパティを持つオブジェクトexport default { fetch: async (request) => { ... } }
名前付き関数宣言export default async function handler(request) { ... }
ベアボディ、エクスポートなしラッパーなしでステートメントを直接記述します

export default を使用するその他のもの(export default class など)は、Save をクリックするとエラーで却下されます。このエラーには、代わりに使用する 2 つの形式が記載されます。検証は保存時に実行されるため、すぐに検出でき、壊れた関数が公開されることはありません。

パスパターン

Path pattern は、どのリクエストが関数を実行するかを決定します。/ で始まる必要があり、最大 2048 文字まで可能です。* は任意の一連の文字にマッチし、? は単一の文字にマッチします。ワイルドカードのないパターンはそのパス自体とその下のすべてにマッチします。

パターンマッチ対象
/*すべてのパス
/api/*/api/ で始まるすべてのパス
/blog/*/comments例えば /blog/my-post/comments
/page/page およびその下のすべて /page/

request オブジェクト

request は標準的な Fetch API Request です。URL、メソッド、ヘッダー、ボディを読み取ることができます:

export default {
  async fetch(request) {
    const url    = new URL(request.url)
    const cookie = request.headers.get('cookie') ?? ''
    const ua     = request.headers.get('user-agent') ?? ''

    if (ua.includes('BadBot')) {
      return new Response('Forbidden', { status: 403 })
    }
  },
}

別のプラットフォームで見たからといって、ヘッダーが存在するものと仮定しないでください。関数が実際に受け取るヘッダーを読み取ってください(関数からログするか、テスト用パスのデバッグレスポンスで返します)。ヘッダーに分岐する前にこれを行ってください。存在しないヘッダーに分岐するハンドラーは、すべてのリクエストで誤ったパスを静かに取ります。

一般的なパターン

古い URL をリダイレクトする

export default {
  async fetch(request) {
    const url = new URL(request.url)
    const redirects = {
      '/old-about':   '/about',
      '/old-contact': '/contact',
    }
    const dest = redirects[url.pathname]
    if (dest) return Response.redirect(url.origin + dest, 301)
  },
}

単純なパスツーパスの移動が少数の場合は、代わりに組み込みのリダイレクトエンジンを使用してください。コードは必要なく、設定は Settings で行われます。Configuring Redirects and Rewrites を参照してください。

セキュリティヘッダーを追加する

export default async function handler(request) {
  const response = await fetch(request)
  const headers = new Headers(response.headers)
  headers.set('X-Frame-Options', 'DENY')
  headers.set('X-Content-Type-Options', 'nosniff')
  headers.set('Referrer-Policy', 'strict-origin-when-cross-origin')
  return new Response(response.body, {
    status: response.status,
    statusText: response.statusText,
    headers,
  })
}

静的なヘッダールールではコードも必要ありません。Settings には、HSTS、CSP、no-embed、no-sniff、referrer policy、CORS のクイック追加プリセット付きのレスポンスヘッダーセクションがあります。

A/B ルーティング

export default {
  async fetch(request) {
    const url     = new URL(request.url)
    const variant = Math.random() < 0.5 ? 'a' : 'b'
    url.searchParams.set('variant', variant)
    return fetch(url.toString(), request)
  },
}

環境スコープ

スコープ実行環境
All environments本番環境、ステージング環境、およびすべてのブランチプレビュー
Production only本番環境
Preview onlyすべての非本番環境

新しい関数を最初に Preview only としてリリースし、ブランチプレビューで動作することを確認してから、All environments に切り替えます。エッジ関数はすべてのリクエストの前で実行されるため、関数内の間違いはすべてのページの間違いになります。

複数の関数の相互作用

プロジェクトのすべての有効な関数は、作成順に評価されます。各リクエストに対して、エッジはリストを調べて、パスパターンがリクエストパスにマッチし、スコープが環境をカバーしている最初の関数を実行します。

  • その関数が Response を返す場合、それが送信され、評価は停止します。
  • 何も返さない場合、評価は次のマッチング関数に続きます。
  • どれもが Response を返さない場合、リクエストはプロジェクトに通常どおり送信されます。

つまり、早期に作成された広い /* 関数は、Response を返す場合、後で作成されたより狭い関数をシャドウできます。特定のものを最初に作成するか、広いものが処理しないパスには何も返さないようにしてください。

デプロイ

Deploy to edge をクリックします。デプロイは、現在のデータベースの状態からエッジネットワーク全体の単一の結合ルーターを再生成するため、関数を有効化、無効化、編集、または削除するとすべてが再公開されます。変更は通常数秒以内に有効になります。

各関数行は Deploy log を保持し、最後のデプロイのステップを表示し、失敗した場合はエラーが表示される DEPLOY FAILED バッジを持ちます。

Pause は関数を削除せずにルーターから外すため、動作が不安定な関数をバックアウトする最速の方法です。Resume はそれを戻します。

関数が例外をスロー した場合

関数内の例外はエッジでキャッチされます。エラーはログされ、リクエストは関数が何も返さなかった場合と同じようにプロジェクトにフォールスルーします。

これはモニタリングシステムではなく、安全ネットです。すべてのリクエストで例外をスロー する関数は、訪問者の観点からはサイレントに失敗し、トラフィックは関数が存在しないかのように単に動作します。関数が意図した効果を失った場合、ルーティングを疑う前に例外を疑ってください。

制限事項

  • プロジェクトあたり最大 20 個の関数。21 番目は却下されます。
  • 関数あたり最大 64 KB のソース。
  • 名前は最大 120 文字、パスパターンは最大 2048 文字です。

関連読資料

それでもお困りですか?

こちらまでメールでお問い合わせください support@kapsulehost.com またはKPanelでチャットを開いてください。

KPanel を開く