HTTP ヘッダーをカスタマイズして送る

Recipe ID: net-003

API 認証やコンテンツネゴシエーションのために、HTTP リクエストにカスタムヘッダーを含めて送信する方法を解説します。
Tauri の plugin-http を使用すれば、ブラウザ標準の fetch と同様の方法でヘッダーを設定・送信できます。

前提条件

この機能を使用するには、@tauri-apps/plugin-http プラグインが必要です。

1. プラグインのインストール

npm run tauri add http

src-tauri/capabilities/default.jsonhttp:default 権限を追加します。
Tauri v2 ではセキュリティの観点から allow: [{ "url": "*" }] のような無制限なワイルドカード指定は許可されていない場合があるため、使用する API のドメインを明示的に指定する必要があります。

以下の例では、コード例で使用する api.myapp.comapi.example.com を許可しています。

{
  "permissions": [
    {
      "identifier": "http:default",
      "allow": [
        { "url": "https://api.myapp.com/*" },
        { "url": "https://api.example.com/*" }
      ],
      "deny": []
    }
  ]
}
注意: 開発中は便利だからと広範囲な許可をしたくなりますが、本番ビルドでは実際に使用するドメインのみを許可することが強く推奨されます。

使用方法

fetch 関数の第2引数の headers プロパティに、キーと値のペアを持つオブジェクトまたは Headers オブジェクトを渡します。

import { fetch } from '@tauri-apps/plugin-http';

await fetch('https://api.example.com/protected', {
    method: 'GET',
    headers: {
        'Authorization': 'Bearer YOUR_TOKEN',
        'X-Custom-Header': 'foobar'
    }
});

コード例

例1: 認証トークン付きリクエスト

Bearer トークンや API キーをヘッダーに含める一般的なパターンです。

import { fetch } from '@tauri-apps/plugin-http';

async function fetchUserData(token: string): Promise<any> {
    try {
        const response = await fetch('https://api.myapp.com/user/profile', {
            method: 'GET',
            headers: {
                // Bearer 認証
                'Authorization': `Bearer ${token}`,
                // クライアントの情報を伝える
                'User-Agent': 'MyTauriApp/1.0.0',
                // レスポンスの形式を指定
                'Accept': 'application/json'
            }
        });

        if (response.ok) {
            return await response.json();
        } else {
            console.error('Unauthorized or Error:', response.status);
        }
    } catch (err) {
        console.error(err);
    }
}

例2: Headers オブジェクトを使用する

Headers クラスを使用すると、ヘッダーの追加・削除や条件付き追加が柔軟に行えます。

import { fetch } from '@tauri-apps/plugin-http';

interface HeaderOptions {
    token?: string;
    locale?: string;
}

async function dynamicHeadersRequest(options: HeaderOptions = {}): Promise<void> {
    const myHeaders = new Headers();
    
    // 基本ヘッダー
    myHeaders.append('Content-Type', 'application/json');
    
    // 条件付きでヘッダーを追加
    if (options.token) {
        myHeaders.append('Authorization', `Bearer ${options.token}`);
    }
    
    if (options.locale) {
        myHeaders.append('Accept-Language', options.locale);
    }

    // 値の上書きも簡単
    myHeaders.set('X-Request-ID', crypto.randomUUID());

    try {
        const response = await fetch('https://api.example.com/data', {
            headers: myHeaders
        });
        
        // ...
    } catch (error) {
        console.error(error);
    }
}

注意点

* Forbidden Headers: ブラウザ (Webview) 上の fetch ではセキュリティ上の理由で一部のヘッダー(Cookie, Host, Content-Length など)は変更できない場合がありますが、Tauri の plugin-http (Rust 経由) であればより柔軟に設定できる場合があります。ただし、プロトコル仕様に反するヘッダー操作は予期せぬ動作を引き起こす可能性があるため注意してください。
* 大文字・小文字: HTTP ヘッダーフィールド名は技術的には大文字と小文字を区別しませんが、慣習的に Content-Type のようにキャピタライズするか、content-type のように全て小文字で扱うことが一般的です。JavaScript のオブジェクトキーとしては区別されるため、統一することをお勧めします。