<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ja">
	<id>http://mochiuwiki.e2.valueserver.jp/index.php?action=history&amp;feed=atom&amp;title=Tauri%E3%81%AE%E5%9F%BA%E7%A4%8E_-_HTTP%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88</id>
	<title>Tauriの基礎 - HTTPクライアント - 版の履歴</title>
	<link rel="self" type="application/atom+xml" href="http://mochiuwiki.e2.valueserver.jp/index.php?action=history&amp;feed=atom&amp;title=Tauri%E3%81%AE%E5%9F%BA%E7%A4%8E_-_HTTP%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88"/>
	<link rel="alternate" type="text/html" href="http://mochiuwiki.e2.valueserver.jp/index.php?title=Tauri%E3%81%AE%E5%9F%BA%E7%A4%8E_-_HTTP%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88&amp;action=history"/>
	<updated>2026-09-06T00:07:53Z</updated>
	<subtitle>このウィキのこのページに関する変更履歴</subtitle>
	<generator>MediaWiki 1.43.6</generator>
	<entry>
		<id>http://mochiuwiki.e2.valueserver.jp/index.php?title=Tauri%E3%81%AE%E5%9F%BA%E7%A4%8E_-_HTTP%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88&amp;diff=14533&amp;oldid=prev</id>
		<title>Wiki: ページの作成:「== 概要 == TauriのHTTPプラグインは、フロントエンドから安全にHTTPリクエストを実行するための公式プラグインである。&lt;br&gt; このプラグインは、Webブラウザ標準のfetch APIと同様のインターフェースを提供しながら、Rustバックエンドを経由してリクエストを実行するため、CORS (Cross-Origin Resource Sharing) の制約を受けないというメリットがある。&lt;br&gt; &lt;br&gt; Tauri v…」</title>
		<link rel="alternate" type="text/html" href="http://mochiuwiki.e2.valueserver.jp/index.php?title=Tauri%E3%81%AE%E5%9F%BA%E7%A4%8E_-_HTTP%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88&amp;diff=14533&amp;oldid=prev"/>
		<updated>2026-03-04T19:47:51Z</updated>

		<summary type="html">&lt;p&gt;ページの作成:「== 概要 == TauriのHTTPプラグインは、フロントエンドから安全にHTTPリクエストを実行するための公式プラグインである。&amp;lt;br&amp;gt; このプラグインは、Webブラウザ標準のfetch APIと同様のインターフェースを提供しながら、Rustバックエンドを経由してリクエストを実行するため、CORS (Cross-Origin Resource Sharing) の制約を受けないというメリットがある。&amp;lt;br&amp;gt; &amp;lt;br&amp;gt; Tauri v…」&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新規ページ&lt;/b&gt;&lt;/p&gt;&lt;div&gt;== 概要 ==&lt;br /&gt;
TauriのHTTPプラグインは、フロントエンドから安全にHTTPリクエストを実行するための公式プラグインである。&amp;lt;br&amp;gt;&lt;br /&gt;
このプラグインは、Webブラウザ標準のfetch APIと同様のインターフェースを提供しながら、Rustバックエンドを経由してリクエストを実行するため、CORS (Cross-Origin Resource Sharing) の制約を受けないというメリットがある。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Tauri v2では、プラグインはRust crateとnpmパッケージの2層構造で提供される。&amp;lt;br&amp;gt;&lt;br /&gt;
Rust側でtauri-plugin-httpクレートが実際のHTTP通信を処理し、フロントエンド側では@tauri-apps/plugin-httpパッケージがTypeScript / JavaScript APIを提供する。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
セキュリティ面では、Capabilities設定によるURLスコープ制御が必須である。&amp;lt;br&amp;gt;&lt;br /&gt;
許可されたドメインに対してのみリクエストを送信できるように設定することにより、悪意あるコードからの保護を実現している。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
このプラグインは主に以下のユースケースで使用される。&amp;lt;br&amp;gt;&lt;br /&gt;
* 外部APIからのデータ取得&lt;br /&gt;
*: REST APIやGraphQLエンドポイントへのアクセスに使用する。&lt;br /&gt;
* ファイルのアップロードとダウンロード&lt;br /&gt;
*: バイナリデータを含むリクエスト / レスポンス処理に対応する。&lt;br /&gt;
* 認証が必要なAPIへのアクセス&lt;br /&gt;
*: ヘッダにトークンを含めたリクエスト送信が可能である。&lt;br /&gt;
* CORS制約を回避したクロスドメイン通信&lt;br /&gt;
*: WebブラウザのCORSポリシーに影響されずにリクエストを送信できる。&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== インストールと設定 ==&lt;br /&gt;
==== プラグインのインストール ====&lt;br /&gt;
HTTPプラグインをプロジェクトに追加するには、以下に示すコマンドを実行する。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
 # Tauri CLIを使用してプラグインを追加&lt;br /&gt;
 npm run tauri add http&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
このコマンドは以下に示す処理を自動的に実行する。&amp;lt;br&amp;gt;&lt;br /&gt;
* Rustクレートの追加&lt;br /&gt;
*: &amp;lt;u&amp;gt;src-tauri/Cargo.toml&amp;lt;/u&amp;gt; ファイルに &amp;lt;u&amp;gt;tauri-plugin-http&amp;lt;/u&amp;gt; が追加される。&lt;br /&gt;
* npmパッケージのインストール&lt;br /&gt;
*: &amp;lt;u&amp;gt;@tauri-apps/plugin-http&amp;lt;/u&amp;gt; がインストールされる。&lt;br /&gt;
* Capabilities設定の生成&lt;br /&gt;
*: デフォルトの権限設定が作成される。&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
手動でインストールする場合は、以下に示す手順を実行する。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
 # npmパッケージのインストール&lt;br /&gt;
 npm install @tauri-apps/plugin-http&lt;br /&gt;
 &lt;br /&gt;
 # Cargo.tomlへの追加&lt;br /&gt;
 # [dependencies]&lt;br /&gt;
 # tauri-plugin-http = &amp;quot;2&amp;quot;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== Rust側の設定 ====&lt;br /&gt;
&amp;lt;u&amp;gt;src-tauri/src/lib.rs&amp;lt;/u&amp;gt; または &amp;lt;u&amp;gt;src-tauri/src/main.rs&amp;lt;/u&amp;gt; でプラグインを登録する。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;rust&amp;quot;&amp;gt;&lt;br /&gt;
 // src-tauri/src/lib.rs&lt;br /&gt;
 fn main() {&lt;br /&gt;
    tauri::Builder::default()&lt;br /&gt;
       .plugin(tauri_plugin_http::init())&lt;br /&gt;
       .run(tauri::generate_context!())&lt;br /&gt;
       .expect(&amp;quot;error while running tauri application&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== Capabilities設定 ====&lt;br /&gt;
HTTPリクエストを許可するURLを設定するために、Capabilitiesファイルを作成または編集する。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
* ファイルの場所&lt;br /&gt;
*: &amp;lt;u&amp;gt;src-tauri/capabilities/default.json&amp;lt;/u&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;$schema&amp;quot;: &amp;quot;../gen/schemas/desktop-schema.json&amp;quot;,&lt;br /&gt;
   &amp;quot;identifier&amp;quot;: &amp;quot;default&amp;quot;,&lt;br /&gt;
   &amp;quot;description&amp;quot;: &amp;quot;Capability for the main window&amp;quot;,&lt;br /&gt;
   &amp;quot;windows&amp;quot;: [&amp;quot;main&amp;quot;],&lt;br /&gt;
   &amp;quot;permissions&amp;quot;: [&lt;br /&gt;
     &amp;quot;core:default&amp;quot;,&lt;br /&gt;
     {&lt;br /&gt;
       &amp;quot;identifier&amp;quot;: &amp;quot;http:default&amp;quot;,&lt;br /&gt;
       &amp;quot;allow&amp;quot;: [&lt;br /&gt;
         {&lt;br /&gt;
           &amp;quot;url&amp;quot;: &amp;quot;https://api.example.com/**&amp;quot;&lt;br /&gt;
         },&lt;br /&gt;
         {&lt;br /&gt;
           &amp;quot;url&amp;quot;: &amp;quot;https://jsonplaceholder.typicode.com/**&amp;quot;&lt;br /&gt;
         }&lt;br /&gt;
       ]&lt;br /&gt;
     }&lt;br /&gt;
   ]&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== URLパターンの指定方法 ====&lt;br /&gt;
URLスコープではglobパターンを使用できる。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ URLパターンの例&lt;br /&gt;
|-&lt;br /&gt;
! パターン !! 説明 !! マッチする例&lt;br /&gt;
|-&lt;br /&gt;
| https://example.com/** || 特定ドメインの全てのパス || https://example.com/api/users&lt;br /&gt;
|-&lt;br /&gt;
| https://*.example.com/** || サブドメインを含む || https://api.example.com/v1&lt;br /&gt;
|-&lt;br /&gt;
| https://example.com/api/v* || バージョニングされたAPI || https://example.com/api/v1&amp;lt;br&amp;gt;https://example.com/api/v2&lt;br /&gt;
|-&lt;br /&gt;
| https://example.com/**/*.json || 特定拡張子のみ || https://example.com/data/config.json&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== fetch APIの基本 ==&lt;br /&gt;
==== 基本的なGETリクエスト ====&lt;br /&gt;
HTTPプラグインの &amp;lt;code&amp;gt;fetch&amp;lt;/code&amp;gt; 関数は、Webブラウザ標準の &amp;lt;code&amp;gt;fetch&amp;lt;/code&amp;gt; とほぼ同じインターフェースを持つ。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
 // components/ApiExample.tsx&lt;br /&gt;
 import { fetch } from &amp;#039;@tauri-apps/plugin-http&amp;#039;;&lt;br /&gt;
 import { useState, useEffect } from &amp;#039;react&amp;#039;;&lt;br /&gt;
 &lt;br /&gt;
 interface User {&lt;br /&gt;
   id: number;&lt;br /&gt;
   name: string;&lt;br /&gt;
   email: string;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 export function ApiExample() {&lt;br /&gt;
   const [users, setUsers] = useState&amp;lt;User[]&amp;gt;([]);&lt;br /&gt;
   const [loading, setLoading] = useState(true);&lt;br /&gt;
   const [error, setError] = useState&amp;lt;string | null&amp;gt;(null);&lt;br /&gt;
 &lt;br /&gt;
   useEffect(() =&amp;gt; {&lt;br /&gt;
     // ユーザ一覧を取得するGETリクエスト&lt;br /&gt;
     async function fetchUsers() {&lt;br /&gt;
       try {&lt;br /&gt;
         const response = await fetch&amp;lt;User[]&amp;gt;(&amp;#039;https://jsonplaceholder.typicode.com/users&amp;#039;);&lt;br /&gt;
 &lt;br /&gt;
         // レスポンスが正常かチェック&lt;br /&gt;
         if (!response.ok) {&lt;br /&gt;
           throw new Error(`HTTP error! status: ${response.status}`);&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // JSONとしてパース&lt;br /&gt;
         const data = await response.json();&lt;br /&gt;
         setUsers(data);&lt;br /&gt;
       }&lt;br /&gt;
       catch (err) {&lt;br /&gt;
         setError(err instanceof Error ? err.message : &amp;#039;Unknown error&amp;#039;);&lt;br /&gt;
       }&lt;br /&gt;
       finally {&lt;br /&gt;
         setLoading(false);&lt;br /&gt;
       }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     fetchUsers();&lt;br /&gt;
   }, []);&lt;br /&gt;
 &lt;br /&gt;
   if (loading) return &amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;;&lt;br /&gt;
   if (error) return &amp;lt;div&amp;gt;Error: {error}&amp;lt;/div&amp;gt;;&lt;br /&gt;
 &lt;br /&gt;
   return (&lt;br /&gt;
     &amp;lt;ul&amp;gt;&lt;br /&gt;
       {users.map(user =&amp;gt; (&lt;br /&gt;
         &amp;lt;li key={user.id}&amp;gt;{user.name} ({user.email})&amp;lt;/li&amp;gt;&lt;br /&gt;
       ))}&lt;br /&gt;
     &amp;lt;/ul&amp;gt;&lt;br /&gt;
   );&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== TypeScript型定義 ====&lt;br /&gt;
HTTPプラグインはTypeScriptに完全対応している。&amp;lt;br&amp;gt;&lt;br /&gt;
ジェネリクスを使用してレスポンスの型を指定できる。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
 // types/api.ts&lt;br /&gt;
 export interface ApiResponse&amp;lt;T&amp;gt; {&lt;br /&gt;
   data: T;&lt;br /&gt;
   status: number;&lt;br /&gt;
   message: string;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 export interface Post {&lt;br /&gt;
   id: number;&lt;br /&gt;
   title: string;&lt;br /&gt;
   body: string;&lt;br /&gt;
   userId: number;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 // api/client.ts&lt;br /&gt;
 import { fetch } from &amp;#039;@tauri-apps/plugin-http&amp;#039;;&lt;br /&gt;
 import type { ApiResponse, Post } from &amp;#039;../types/api&amp;#039;;&lt;br /&gt;
 &lt;br /&gt;
 // 型安全なfetchラッパー関数&lt;br /&gt;
 async function fetchTyped&amp;lt;T&amp;gt;(url: string): Promise&amp;lt;T&amp;gt; {&lt;br /&gt;
   const response = await fetch(url);&lt;br /&gt;
 &lt;br /&gt;
   if (!response.ok) {&lt;br /&gt;
     throw new Error(`HTTP ${response.status}: ${response.statusText}`);&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   return response.json() as Promise&amp;lt;T&amp;gt;;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 // 使用例&lt;br /&gt;
 async function getPosts(): Promise&amp;lt;Post[]&amp;gt; {&lt;br /&gt;
   return fetchTyped&amp;lt;Post[]&amp;gt;(&amp;#039;https://jsonplaceholder.typicode.com/posts&amp;#039;);&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== リクエスト設定 ==&lt;br /&gt;
==== HTTPメソッド ====&lt;br /&gt;
GET以外のHTTPメソッドを使用する場合は、&amp;lt;code&amp;gt;method&amp;lt;/code&amp;gt; オプションを指定する。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
 // api/httpMethods.ts&lt;br /&gt;
 import { fetch } from &amp;#039;@tauri-apps/plugin-http&amp;#039;;&lt;br /&gt;
 &lt;br /&gt;
 const BASE_URL = &amp;#039;https://jsonplaceholder.typicode.com&amp;#039;;&lt;br /&gt;
 &lt;br /&gt;
 // POSTリクエスト : 新規作成&lt;br /&gt;
 export async function createPost(title: string, body: string, userId: number) {&lt;br /&gt;
   const response = await fetch(`${BASE_URL}/posts`, {&lt;br /&gt;
     method: &amp;#039;POST&amp;#039;,&lt;br /&gt;
     headers: {&lt;br /&gt;
       &amp;#039;Content-Type&amp;#039;: &amp;#039;application/json&amp;#039;,&lt;br /&gt;
     },&lt;br /&gt;
     body: JSON.stringify({&lt;br /&gt;
       title,&lt;br /&gt;
       body,&lt;br /&gt;
       userId,&lt;br /&gt;
     }),&lt;br /&gt;
   });&lt;br /&gt;
 &lt;br /&gt;
   return response.json();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 // PUTリクエスト : 全体更新&lt;br /&gt;
 export async function updatePost(id: number, data: { title: string; body: string }) {&lt;br /&gt;
   const response = await fetch(`${BASE_URL}/posts/${id}`, {&lt;br /&gt;
     method: &amp;#039;PUT&amp;#039;,&lt;br /&gt;
     headers: {&lt;br /&gt;
       &amp;#039;Content-Type&amp;#039;: &amp;#039;application/json&amp;#039;,&lt;br /&gt;
     },&lt;br /&gt;
     body: JSON.stringify(data),&lt;br /&gt;
   });&lt;br /&gt;
 &lt;br /&gt;
   return response.json();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 // PATCHリクエスト : 部分更新&lt;br /&gt;
 export async function patchPost(id: number, data: Partial&amp;lt;{ title: string; body: string }&amp;gt;) {&lt;br /&gt;
   const response = await fetch(`${BASE_URL}/posts/${id}`, {&lt;br /&gt;
     method: &amp;#039;PATCH&amp;#039;,&lt;br /&gt;
     headers: {&lt;br /&gt;
       &amp;#039;Content-Type&amp;#039;: &amp;#039;application/json&amp;#039;,&lt;br /&gt;
     },&lt;br /&gt;
     body: JSON.stringify(data),&lt;br /&gt;
   });&lt;br /&gt;
 &lt;br /&gt;
   return response.json();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 // DELETEリクエスト : 削除&lt;br /&gt;
 export async function deletePost(id: number): Promise&amp;lt;boolean&amp;gt; {&lt;br /&gt;
   const response = await fetch(`${BASE_URL}/posts/${id}`, {&lt;br /&gt;
     method: &amp;#039;DELETE&amp;#039;,&lt;br /&gt;
   });&lt;br /&gt;
 &lt;br /&gt;
   return response.ok;&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== ヘッダの設定 ====&lt;br /&gt;
カスタムヘッダを設定することにより、認証トークンの送信やコンテンツタイプの指定が可能である。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
 // api/authClient.ts&lt;br /&gt;
 import { fetch } from &amp;#039;@tauri-apps/plugin-http&amp;#039;;&lt;br /&gt;
 &lt;br /&gt;
 // 認証トークンを含むAPIクライアント&lt;br /&gt;
 export class AuthApiClient {&lt;br /&gt;
   private baseUrl: string;&lt;br /&gt;
   private token: string | null = null;&lt;br /&gt;
 &lt;br /&gt;
   constructor(baseUrl: string) {&lt;br /&gt;
     this.baseUrl = baseUrl;&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   // トークンを設定&lt;br /&gt;
   setToken(token: string) {&lt;br /&gt;
     this.token = token;&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   // 共通ヘッダを生成&lt;br /&gt;
   private getHeaders(): HeadersInit {&lt;br /&gt;
     const headers: HeadersInit = {&lt;br /&gt;
       &amp;#039;Content-Type&amp;#039;: &amp;#039;application/json&amp;#039;,&lt;br /&gt;
       &amp;#039;Accept&amp;#039;: &amp;#039;application/json&amp;#039;,&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     // トークンが設定されている場合はAuthorizationヘッダを追加&lt;br /&gt;
     if (this.token) {&lt;br /&gt;
       headers[&amp;#039;Authorization&amp;#039;] = `Bearer ${this.token}`;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     return headers;&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   // GETリクエスト&lt;br /&gt;
   async get&amp;lt;T&amp;gt;(endpoint: string): Promise&amp;lt;T&amp;gt; {&lt;br /&gt;
     const response = await fetch(`${this.baseUrl}${endpoint}`, {&lt;br /&gt;
       method: &amp;#039;GET&amp;#039;,&lt;br /&gt;
       headers: this.getHeaders(),&lt;br /&gt;
     });&lt;br /&gt;
 &lt;br /&gt;
     if (!response.ok) {&lt;br /&gt;
       throw new Error(`API Error: ${response.status}`);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     return response.json();&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   // POSTリクエスト&lt;br /&gt;
   async post&amp;lt;T&amp;gt;(endpoint: string, data: unknown): Promise&amp;lt;T&amp;gt; {&lt;br /&gt;
     const response = await fetch(`${this.baseUrl}${endpoint}`, {&lt;br /&gt;
       method: &amp;#039;POST&amp;#039;,&lt;br /&gt;
       headers: this.getHeaders(),&lt;br /&gt;
       body: JSON.stringify(data),&lt;br /&gt;
     });&lt;br /&gt;
 &lt;br /&gt;
     if (!response.ok) {&lt;br /&gt;
       throw new Error(`API Error: ${response.status}`);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     return response.json();&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== ボディの設定 ====&lt;br /&gt;
リクエストボディは文字列、JSON、FormData等、様々な形式に対応している。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
 // api/upload.ts&lt;br /&gt;
 import { fetch } from &amp;#039;@tauri-apps/plugin-http&amp;#039;;&lt;br /&gt;
 &lt;br /&gt;
 // JSONデータの送信&lt;br /&gt;
 export async function sendJson(data: object) {&lt;br /&gt;
   const response = await fetch(&amp;#039;https://api.example.com/data&amp;#039;, {&lt;br /&gt;
     method: &amp;#039;POST&amp;#039;,&lt;br /&gt;
     headers: {&lt;br /&gt;
       &amp;#039;Content-Type&amp;#039;: &amp;#039;application/json&amp;#039;,&lt;br /&gt;
     },&lt;br /&gt;
     body: JSON.stringify(data),&lt;br /&gt;
   });&lt;br /&gt;
 &lt;br /&gt;
   return response.json();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 // FormDataを使用したファイルアップロード&lt;br /&gt;
 export async function uploadFile(file: File, metadata: { name: string; description: string }) {&lt;br /&gt;
   const formData = new FormData();&lt;br /&gt;
   formData.append(&amp;#039;file&amp;#039;, file);&lt;br /&gt;
   formData.append(&amp;#039;name&amp;#039;, metadata.name);&lt;br /&gt;
   formData.append(&amp;#039;description&amp;#039;, metadata.description);&lt;br /&gt;
 &lt;br /&gt;
   const response = await fetch(&amp;#039;https://api.example.com/upload&amp;#039;, {&lt;br /&gt;
     method: &amp;#039;POST&amp;#039;,&lt;br /&gt;
     // FormDataを使用する場合はContent-Typeを設定しない&lt;br /&gt;
     // ブラウザが自動的にmultipart/form-dataを設定する&lt;br /&gt;
     body: formData,&lt;br /&gt;
   });&lt;br /&gt;
 &lt;br /&gt;
   return response.json();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 // テキストデータの送信&lt;br /&gt;
 export async function sendText(text: string) {&lt;br /&gt;
   const response = await fetch(&amp;#039;https://api.example.com/text&amp;#039;, {&lt;br /&gt;
     method: &amp;#039;POST&amp;#039;,&lt;br /&gt;
     headers: {&lt;br /&gt;
       &amp;#039;Content-Type&amp;#039;: &amp;#039;text/plain&amp;#039;,&lt;br /&gt;
     },&lt;br /&gt;
     body: text,&lt;br /&gt;
   });&lt;br /&gt;
 &lt;br /&gt;
   return response.text();&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== タイムアウト設定 ====&lt;br /&gt;
&amp;lt;code&amp;gt;signal&amp;lt;/code&amp;gt; オプション と &amp;lt;code&amp;gt;AbortController&amp;lt;/code&amp;gt; を使用してタイムアウトを定義することができる。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
 // utils/timeoutFetch.ts&lt;br /&gt;
 import { fetch, Response } from &amp;#039;@tauri-apps/plugin-http&amp;#039;;&lt;br /&gt;
 &lt;br /&gt;
 // タイムアウト付きfetch&lt;br /&gt;
 export async function fetchWithTimeout(&lt;br /&gt;
   url: string,&lt;br /&gt;
   options: RequestInit &amp;amp; { timeout?: number } = {}&lt;br /&gt;
 ): Promise&amp;lt;Response&amp;gt; {&lt;br /&gt;
   const { timeout = 5000, ...fetchOptions } = options;&lt;br /&gt;
 &lt;br /&gt;
   const controller = new AbortController();&lt;br /&gt;
   const timeoutId = setTimeout(() =&amp;gt; controller.abort(), timeout);&lt;br /&gt;
 &lt;br /&gt;
   try {&lt;br /&gt;
     const response = await fetch(url, {&lt;br /&gt;
       ...fetchOptions,&lt;br /&gt;
       signal: controller.signal,&lt;br /&gt;
     });&lt;br /&gt;
 &lt;br /&gt;
     return response;&lt;br /&gt;
   }&lt;br /&gt;
   finally {&lt;br /&gt;
     clearTimeout(timeoutId);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 // 使用例&lt;br /&gt;
 async function fetchWithRetry() {&lt;br /&gt;
   try {&lt;br /&gt;
     const response = await fetchWithTimeout(&amp;#039;https://api.example.com/data&amp;#039;, {&lt;br /&gt;
       method: &amp;#039;GET&amp;#039;,&lt;br /&gt;
       timeout: 10000, // 10秒でタイムアウト&lt;br /&gt;
     });&lt;br /&gt;
 &lt;br /&gt;
     return response.json();&lt;br /&gt;
   }&lt;br /&gt;
   catch (error) {&lt;br /&gt;
     if (error instanceof Error &amp;amp;&amp;amp; error.name === &amp;#039;AbortError&amp;#039;) {&lt;br /&gt;
       console.error(&amp;#039;Request timed out&amp;#039;);&lt;br /&gt;
     }&lt;br /&gt;
     throw error;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== レスポンス処理 ==&lt;br /&gt;
==== JSONのパース ====&lt;br /&gt;
&amp;lt;code&amp;gt;response.json()&amp;lt;/code&amp;gt; メソッドでJSONレスポンスをパースする。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
 // api/responseHandler.ts&lt;br /&gt;
 import { fetch } from &amp;#039;@tauri-apps/plugin-http&amp;#039;;&lt;br /&gt;
 &lt;br /&gt;
 interface ApiResponse&amp;lt;T&amp;gt; {&lt;br /&gt;
   success: boolean;&lt;br /&gt;
   data: T;&lt;br /&gt;
   error?: string;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 export async function parseJsonResponse&amp;lt;T&amp;gt;(response: Response): Promise&amp;lt;T&amp;gt; {&lt;br /&gt;
   // レスポンスボディをテキストとして取得&lt;br /&gt;
   const text = await response.text();&lt;br /&gt;
 &lt;br /&gt;
   // 空のレスポンスの場合&lt;br /&gt;
   if (!text) {&lt;br /&gt;
     if (response.ok) {&lt;br /&gt;
       return {} as T;&lt;br /&gt;
     }&lt;br /&gt;
     throw new Error(`HTTP ${response.status}: Empty response`);&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   // JSONとしてパース&lt;br /&gt;
   try {&lt;br /&gt;
     const json = JSON.parse(text);&lt;br /&gt;
 &lt;br /&gt;
     if (!response.ok) {&lt;br /&gt;
       // APIエラーレスポンスの場合&lt;br /&gt;
       const errorMessage = json.error || json.message || `HTTP ${response.status}`;&lt;br /&gt;
       throw new Error(errorMessage);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     return json as T;&lt;br /&gt;
   }&lt;br /&gt;
   catch (e) {&lt;br /&gt;
     if (e instanceof SyntaxError) {&lt;br /&gt;
       throw new Error(&amp;#039;Invalid JSON response&amp;#039;);&lt;br /&gt;
     }&lt;br /&gt;
     throw e;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== ステータスコードの確認 ====&lt;br /&gt;
HTTPステータスコードに基づいて処理を分岐させる。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
 // utils/statusHandler.ts&lt;br /&gt;
 import { fetch, Response } from &amp;#039;@tauri-apps/plugin-http&amp;#039;;&lt;br /&gt;
 &lt;br /&gt;
 export class HttpError extends Error {&lt;br /&gt;
   constructor(&lt;br /&gt;
     public status: number,&lt;br /&gt;
     public statusText: string,&lt;br /&gt;
     public body?: string&lt;br /&gt;
   ) {&lt;br /&gt;
     super(`HTTP ${status}: ${statusText}`);&lt;br /&gt;
     this.name = &amp;#039;HttpError&amp;#039;;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 export async function handleResponse&amp;lt;T&amp;gt;(response: Response): Promise&amp;lt;T&amp;gt; {&lt;br /&gt;
   // ステータスコードによる分岐&lt;br /&gt;
   if (response.status &amp;gt;= 200 &amp;amp;&amp;amp; response.status &amp;lt; 300) {&lt;br /&gt;
     // 成功レスポンス (2xx)&lt;br /&gt;
     return response.json();&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   // エラーレスポンスの処理&lt;br /&gt;
   const body = await response.text();&lt;br /&gt;
 &lt;br /&gt;
   switch (response.status) {&lt;br /&gt;
     case 400:&lt;br /&gt;
       throw new HttpError(400, &amp;#039;Bad Request&amp;#039;, body);&lt;br /&gt;
     case 401:&lt;br /&gt;
       throw new HttpError(401, &amp;#039;Unauthorized&amp;#039;, body);&lt;br /&gt;
     case 403:&lt;br /&gt;
       throw new HttpError(403, &amp;#039;Forbidden&amp;#039;, body);&lt;br /&gt;
     case 404:&lt;br /&gt;
       throw new HttpError(404, &amp;#039;Not Found&amp;#039;, body);&lt;br /&gt;
     case 500:&lt;br /&gt;
       throw new HttpError(500, &amp;#039;Internal Server Error&amp;#039;, body);&lt;br /&gt;
     case 502:&lt;br /&gt;
       throw new HttpError(502, &amp;#039;Bad Gateway&amp;#039;, body);&lt;br /&gt;
     case 503:&lt;br /&gt;
       throw new HttpError(503, &amp;#039;Service Unavailable&amp;#039;, body);&lt;br /&gt;
     default:&lt;br /&gt;
       throw new HttpError(response.status, response.statusText, body);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== エラーハンドリング ====&lt;br /&gt;
包括的なエラーハンドリングの定義例を示す。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
 // hooks/useApi.ts&lt;br /&gt;
 import { fetch } from &amp;#039;@tauri-apps/plugin-http&amp;#039;;&lt;br /&gt;
 import { useState, useCallback } from &amp;#039;react&amp;#039;;&lt;br /&gt;
 &lt;br /&gt;
 interface UseApiResult&amp;lt;T&amp;gt; {&lt;br /&gt;
   data: T | null;&lt;br /&gt;
   loading: boolean;&lt;br /&gt;
   error: Error | null;&lt;br /&gt;
   execute: () =&amp;gt; Promise&amp;lt;void&amp;gt;;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 export function useApi&amp;lt;T&amp;gt;(&lt;br /&gt;
   url: string,&lt;br /&gt;
   options?: RequestInit&lt;br /&gt;
 ): UseApiResult&amp;lt;T&amp;gt; {&lt;br /&gt;
   const [data, setData] = useState&amp;lt;T | null&amp;gt;(null);&lt;br /&gt;
   const [loading, setLoading] = useState(false);&lt;br /&gt;
   const [error, setError] = useState&amp;lt;Error | null&amp;gt;(null);&lt;br /&gt;
 &lt;br /&gt;
   const execute = useCallback(async () =&amp;gt; {&lt;br /&gt;
     setLoading(true);&lt;br /&gt;
     setError(null);&lt;br /&gt;
 &lt;br /&gt;
     try {&lt;br /&gt;
       const response = await fetch(url, options);&lt;br /&gt;
 &lt;br /&gt;
       if (!response.ok) {&lt;br /&gt;
         const errorText = await response.text();&lt;br /&gt;
         throw new Error(`HTTP ${response.status}: ${errorText}`);&lt;br /&gt;
       }&lt;br /&gt;
 &lt;br /&gt;
       const result = await response.json();&lt;br /&gt;
       setData(result);&lt;br /&gt;
     }&lt;br /&gt;
     catch (err) {&lt;br /&gt;
       // ネットワークエラー、タイムアウト、JSONパースエラー等&lt;br /&gt;
       if (err instanceof Error) {&lt;br /&gt;
         setError(err);&lt;br /&gt;
       }&lt;br /&gt;
       else {&lt;br /&gt;
         setError(new Error(&amp;#039;Unknown error occurred&amp;#039;));&lt;br /&gt;
       }&lt;br /&gt;
     }&lt;br /&gt;
     finally {&lt;br /&gt;
       setLoading(false);&lt;br /&gt;
     }&lt;br /&gt;
   }, [url, options]);&lt;br /&gt;
 &lt;br /&gt;
   return { data, loading, error, execute };&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 // 使用例&lt;br /&gt;
 function UserProfile({ userId }: { userId: number }) {&lt;br /&gt;
   const { data: user, loading, error, execute } = useApi&amp;lt;User&amp;gt;(&lt;br /&gt;
     `https://jsonplaceholder.typicode.com/users/${userId}`&lt;br /&gt;
   );&lt;br /&gt;
 &lt;br /&gt;
   if (loading) return &amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;;&lt;br /&gt;
   if (error) return &amp;lt;div&amp;gt;Error: {error.message}&amp;lt;/div&amp;gt;;&lt;br /&gt;
 &lt;br /&gt;
   return (&lt;br /&gt;
     &amp;lt;div&amp;gt;&lt;br /&gt;
       &amp;lt;h1&amp;gt;{user?.name}&amp;lt;/h1&amp;gt;&lt;br /&gt;
       &amp;lt;button onClick={execute}&amp;gt;Reload&amp;lt;/button&amp;gt;&lt;br /&gt;
     &amp;lt;/div&amp;gt;&lt;br /&gt;
   );&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== URLスコープによるアクセス制御 ==&lt;br /&gt;
==== セキュリティの重要性 ====&lt;br /&gt;
HTTPプラグインはRustバックエンドを経由してリクエストを送信するため、WebブラウザのCORS制約を受けない。&amp;lt;br&amp;gt;&lt;br /&gt;
このメリットは強力だが、同時にセキュリティリスクも伴う。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
URLスコープを適切に設定しない場合、アプリケーション内の悪意あるコードが任意のサーバにデータを送信できる可能性がある。&amp;lt;br&amp;gt;&lt;br /&gt;
そのため、必要最小限のドメインのみを許可することが重要である。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== Capabilitiesファイルの設定 ====&lt;br /&gt;
&amp;lt;code&amp;gt;src-tauri/capabilities/&amp;lt;/code&amp;gt; ディレクトリにJSONファイルを作成して権限を設定する。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;$schema&amp;quot;: &amp;quot;../gen/schemas/desktop-schema.json&amp;quot;,&lt;br /&gt;
   &amp;quot;identifier&amp;quot;: &amp;quot;http-capability&amp;quot;,&lt;br /&gt;
   &amp;quot;description&amp;quot;: &amp;quot;HTTP client capability for API access&amp;quot;,&lt;br /&gt;
   &amp;quot;windows&amp;quot;: [&amp;quot;main&amp;quot;],&lt;br /&gt;
   &amp;quot;permissions&amp;quot;: [&lt;br /&gt;
     {&lt;br /&gt;
       &amp;quot;identifier&amp;quot;: &amp;quot;http:default&amp;quot;,&lt;br /&gt;
       &amp;quot;allow&amp;quot;: [&lt;br /&gt;
         {&lt;br /&gt;
           &amp;quot;url&amp;quot;: &amp;quot;https://api.myapp.com/v1/**&amp;quot;&lt;br /&gt;
         },&lt;br /&gt;
         {&lt;br /&gt;
           &amp;quot;url&amp;quot;: &amp;quot;https://cdn.myapp.com/**&amp;quot;&lt;br /&gt;
         },&lt;br /&gt;
         {&lt;br /&gt;
           &amp;quot;url&amp;quot;: &amp;quot;https://*.cloudfront.net/**&amp;quot;&lt;br /&gt;
         }&lt;br /&gt;
       ],&lt;br /&gt;
       &amp;quot;deny&amp;quot;: [&lt;br /&gt;
         {&lt;br /&gt;
           &amp;quot;url&amp;quot;: &amp;quot;https://api.myapp.com/v1/admin/**&amp;quot;&lt;br /&gt;
         }&lt;br /&gt;
       ]&lt;br /&gt;
     }&lt;br /&gt;
   ]&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== 複数環境の設定 ====&lt;br /&gt;
開発環境と本番環境で異なるURLを許可する場合の設定例を示す。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
 // src-tauri/capabilities/development.json&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;identifier&amp;quot;: &amp;quot;development&amp;quot;,&lt;br /&gt;
   &amp;quot;description&amp;quot;: &amp;quot;Development environment capabilities&amp;quot;,&lt;br /&gt;
   &amp;quot;windows&amp;quot;: [&amp;quot;main&amp;quot;],&lt;br /&gt;
   &amp;quot;permissions&amp;quot;: [&lt;br /&gt;
     {&lt;br /&gt;
       &amp;quot;identifier&amp;quot;: &amp;quot;http:default&amp;quot;,&lt;br /&gt;
       &amp;quot;allow&amp;quot;: [&lt;br /&gt;
         { &amp;quot;url&amp;quot;: &amp;quot;http://localhost:*&amp;quot; },&lt;br /&gt;
         { &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:*&amp;quot; },&lt;br /&gt;
         { &amp;quot;url&amp;quot;: &amp;quot;https://dev-api.myapp.com/**&amp;quot; }&lt;br /&gt;
       ]&lt;br /&gt;
     }&lt;br /&gt;
   ]&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 // src-tauri/capabilities/production.json&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;identifier&amp;quot;: &amp;quot;production&amp;quot;,&lt;br /&gt;
   &amp;quot;description&amp;quot;: &amp;quot;Production environment capabilities&amp;quot;,&lt;br /&gt;
   &amp;quot;windows&amp;quot;: [&amp;quot;main&amp;quot;],&lt;br /&gt;
   &amp;quot;permissions&amp;quot;: [&lt;br /&gt;
     {&lt;br /&gt;
       &amp;quot;identifier&amp;quot;: &amp;quot;http:default&amp;quot;,&lt;br /&gt;
       &amp;quot;allow&amp;quot;: [&lt;br /&gt;
         { &amp;quot;url&amp;quot;: &amp;quot;https://api.myapp.com/**&amp;quot; }&lt;br /&gt;
       ]&lt;br /&gt;
     }&lt;br /&gt;
   ]&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Rust側reqwestとの使い分け ==&lt;br /&gt;
==== フロントエンドでHTTPプラグインを使用するケース ====&lt;br /&gt;
以下に示すような場合は、HTTPプラグインの使用が適している。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
* UIと密接に連携するAPI呼び出し&lt;br /&gt;
*: コンポーネント内で直接データを取得・表示する場合&lt;br /&gt;
* ユーザ操作に応じたリクエスト&lt;br /&gt;
*: ボタンクリックやフォーム送信に伴うAPI呼び出し。&lt;br /&gt;
* 簡易的なAPIクライアント&lt;br /&gt;
*: 複雑なバックエンド処理が不要な場合&lt;br /&gt;
* React Query等の状態管理ライブラリとの連携&lt;br /&gt;
*: フロントエンドでキャッシュや状態を管理する場合&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== Rust側でreqwestを使用するケース ====&lt;br /&gt;
以下に示すような場合は、Rust側で &amp;lt;u&amp;gt;reqwest&amp;lt;/u&amp;gt; クレートを使用することが適している。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
* 重い処理を伴うAPI呼び出し&lt;br /&gt;
*: レスポンスの解析や変換にCPU集約的な処理が必要な場合&lt;br /&gt;
* 機密情報を含むリクエスト&lt;br /&gt;
*: APIキーやシークレットを安全に扱う必要がある場合&lt;br /&gt;
* バックグラウンドでの定期実行&lt;br /&gt;
*: ユーザ操作とは無関係に定期的にデータを同期する場合&lt;br /&gt;
* 複雑な認証フロー&lt;br /&gt;
*: OAuthや複雑なトークン更新ロジックが必要な場合&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== Rust側でのHTTPリクエスト ====&lt;br /&gt;
* Rust側&lt;br /&gt;
*: &amp;lt;syntaxhighlight lang=&amp;quot;rust&amp;quot;&amp;gt;&lt;br /&gt;
 // src-tauri/src/commands/api.rs&lt;br /&gt;
 use reqwest;&lt;br /&gt;
 use serde::{Deserialize, Serialize};&lt;br /&gt;
 &lt;br /&gt;
 #[derive(Debug, Serialize, Deserialize)]&lt;br /&gt;
 pub struct ApiResponse&amp;lt;T&amp;gt; {&lt;br /&gt;
    pub data: T,&lt;br /&gt;
    pub status: u16,&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 // TauriコマンドとしてAPI呼び出しを提供&lt;br /&gt;
 #[tauri::command]&lt;br /&gt;
 pub async fn fetch_from_backend(url: String) -&amp;gt; Result&amp;lt;String, String&amp;gt; {&lt;br /&gt;
    let client = reqwest::Client::new();&lt;br /&gt;
 &lt;br /&gt;
    let response = client&lt;br /&gt;
       .get(&amp;amp;url)&lt;br /&gt;
       .header(&amp;quot;Authorization&amp;quot;, &amp;quot;Bearer SECRET_TOKEN&amp;quot;) // 安全にトークンを扱える&lt;br /&gt;
       .send()&lt;br /&gt;
       .await&lt;br /&gt;
       .map_err(|e| e.to_string())?;&lt;br /&gt;
 &lt;br /&gt;
    let body = response.text().await.map_err(|e| e.to_string())?;&lt;br /&gt;
 &lt;br /&gt;
    Ok(body)&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
*: &amp;lt;br&amp;gt;&lt;br /&gt;
* TypeScript側からの呼び出し&lt;br /&gt;
*: &amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
 import { invoke } from &amp;#039;@tauri-apps/api/core&amp;#039;;&lt;br /&gt;
 &lt;br /&gt;
 async function fetchDataSecurely() {&lt;br /&gt;
   const result = await invoke&amp;lt;string&amp;gt;(&amp;#039;fetch_from_backend&amp;#039;, {&lt;br /&gt;
     url: &amp;#039;https://api.example.com/secure-data&amp;#039;,&lt;br /&gt;
   });&lt;br /&gt;
 &lt;br /&gt;
   return JSON.parse(result);&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== サンプルコード ==&lt;br /&gt;
==== APIクライアントクラスの定義 ====&lt;br /&gt;
再利用可能なAPIクライアントクラスの定義例を示す。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
 // lib/apiClient.ts&lt;br /&gt;
 import { fetch, Response } from &amp;#039;@tauri-apps/plugin-http&amp;#039;;&lt;br /&gt;
 &lt;br /&gt;
 export interface RequestConfig {&lt;br /&gt;
   method?: &amp;#039;GET&amp;#039; | &amp;#039;POST&amp;#039; | &amp;#039;PUT&amp;#039; | &amp;#039;PATCH&amp;#039; | &amp;#039;DELETE&amp;#039;;&lt;br /&gt;
   headers?: Record&amp;lt;string, string&amp;gt;;&lt;br /&gt;
   body?: unknown;&lt;br /&gt;
   timeout?: number;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 export class ApiClient {&lt;br /&gt;
   private baseUrl: string;&lt;br /&gt;
   private defaultHeaders: Record&amp;lt;string, string&amp;gt;;&lt;br /&gt;
 &lt;br /&gt;
   constructor(baseUrl: string, defaultHeaders: Record&amp;lt;string, string&amp;gt; = {}) {&lt;br /&gt;
     this.baseUrl = baseUrl;&lt;br /&gt;
     this.defaultHeaders = {&lt;br /&gt;
       &amp;#039;Content-Type&amp;#039;: &amp;#039;application/json&amp;#039;,&lt;br /&gt;
       ...defaultHeaders,&lt;br /&gt;
     };&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   // ベースURLを設定&lt;br /&gt;
   setBaseUrl(url: string): void {&lt;br /&gt;
     this.baseUrl = url;&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   // デフォルトヘッダを更新&lt;br /&gt;
   setDefaultHeader(key: string, value: string): void {&lt;br /&gt;
     this.defaultHeaders[key] = value;&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   // 汎用リクエストメソッド&lt;br /&gt;
   async request&amp;lt;T&amp;gt;(endpoint: string, config: RequestConfig = {}): Promise&amp;lt;T&amp;gt; {&lt;br /&gt;
     const { method = &amp;#039;GET&amp;#039;, headers = {}, body, timeout } = config;&lt;br /&gt;
 &lt;br /&gt;
     const controller = new AbortController();&lt;br /&gt;
     const timeoutId = timeout ? setTimeout(() =&amp;gt; controller.abort(), timeout) : null;&lt;br /&gt;
 &lt;br /&gt;
     try {&lt;br /&gt;
       const response = await fetch(`${this.baseUrl}${endpoint}`, {&lt;br /&gt;
         method,&lt;br /&gt;
         headers: { ...this.defaultHeaders, ...headers },&lt;br /&gt;
         body: body ? JSON.stringify(body) : undefined,&lt;br /&gt;
         signal: controller.signal,&lt;br /&gt;
       });&lt;br /&gt;
 &lt;br /&gt;
       return this.handleResponse&amp;lt;T&amp;gt;(response);&lt;br /&gt;
     }&lt;br /&gt;
     finally {&lt;br /&gt;
       if (timeoutId) clearTimeout(timeoutId);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   // レスポンス処理&lt;br /&gt;
   private async handleResponse&amp;lt;T&amp;gt;(response: Response): Promise&amp;lt;T&amp;gt; {&lt;br /&gt;
     if (!response.ok) {&lt;br /&gt;
       const errorBody = await response.text();&lt;br /&gt;
       throw new Error(`HTTP ${response.status}: ${errorBody}`);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // 空のレスポンス対応&lt;br /&gt;
     const text = await response.text();&lt;br /&gt;
     return text ? JSON.parse(text) : ({} as T);&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   // 便利なメソッド&lt;br /&gt;
   get&amp;lt;T&amp;gt;(endpoint: string, config?: Omit&amp;lt;RequestConfig, &amp;#039;method&amp;#039; | &amp;#039;body&amp;#039;&amp;gt;): Promise&amp;lt;T&amp;gt; {&lt;br /&gt;
     return this.request&amp;lt;T&amp;gt;(endpoint, { ...config, method: &amp;#039;GET&amp;#039; });&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   post&amp;lt;T&amp;gt;(endpoint: string, body: unknown, config?: Omit&amp;lt;RequestConfig, &amp;#039;method&amp;#039;&amp;gt;): Promise&amp;lt;T&amp;gt; {&lt;br /&gt;
     return this.request&amp;lt;T&amp;gt;(endpoint, { ...config, method: &amp;#039;POST&amp;#039;, body });&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   put&amp;lt;T&amp;gt;(endpoint: string, body: unknown, config?: Omit&amp;lt;RequestConfig, &amp;#039;method&amp;#039;&amp;gt;): Promise&amp;lt;T&amp;gt; {&lt;br /&gt;
     return this.request&amp;lt;T&amp;gt;(endpoint, { ...config, method: &amp;#039;PUT&amp;#039;, body });&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   delete&amp;lt;T&amp;gt;(endpoint: string, config?: Omit&amp;lt;RequestConfig, &amp;#039;method&amp;#039;&amp;gt;): Promise&amp;lt;T&amp;gt; {&lt;br /&gt;
     return this.request&amp;lt;T&amp;gt;(endpoint, { ...config, method: &amp;#039;DELETE&amp;#039; });&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== 認証付きリクエスト ====&lt;br /&gt;
認証トークンを管理する拡張APIクライアントの定義例を示す。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
 // lib/authApiClient.ts&lt;br /&gt;
 import { ApiClient } from &amp;#039;./apiClient&amp;#039;;&lt;br /&gt;
 &lt;br /&gt;
 interface TokenPair {&lt;br /&gt;
   accessToken: string;&lt;br /&gt;
   refreshToken: string;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 interface LoginResponse {&lt;br /&gt;
   user: { id: number; name: string; email: string };&lt;br /&gt;
   tokens: TokenPair;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 export class AuthApiClient extends ApiClient {&lt;br /&gt;
   private tokens: TokenPair | null = null;&lt;br /&gt;
 &lt;br /&gt;
   constructor(baseUrl: string) {&lt;br /&gt;
     super(baseUrl);&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   // ログイン&lt;br /&gt;
   async login(email: string, password: string): Promise&amp;lt;LoginResponse&amp;gt; {&lt;br /&gt;
     const response = await this.post&amp;lt;LoginResponse&amp;gt;(&amp;#039;/auth/login&amp;#039;, { email, password });&lt;br /&gt;
 &lt;br /&gt;
     this.tokens = response.tokens;&lt;br /&gt;
     this.setDefaultHeader(&amp;#039;Authorization&amp;#039;, `Bearer ${this.tokens.accessToken}`);&lt;br /&gt;
 &lt;br /&gt;
     return response;&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   // ログアウト&lt;br /&gt;
   logout(): void {&lt;br /&gt;
     this.tokens = null;&lt;br /&gt;
     this.setDefaultHeader(&amp;#039;Authorization&amp;#039;, &amp;#039;&amp;#039;);&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   // トークンリフレッシュ&lt;br /&gt;
   async refreshToken(): Promise&amp;lt;void&amp;gt; {&lt;br /&gt;
     if (!this.tokens?.refreshToken) {&lt;br /&gt;
       throw new Error(&amp;#039;No refresh token available&amp;#039;);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     const response = await this.post&amp;lt;TokenPair&amp;gt;(&amp;#039;/auth/refresh&amp;#039;, {&lt;br /&gt;
       refreshToken: this.tokens.refreshToken,&lt;br /&gt;
     });&lt;br /&gt;
 &lt;br /&gt;
     this.tokens = response;&lt;br /&gt;
     this.setDefaultHeader(&amp;#039;Authorization&amp;#039;, `Bearer ${this.tokens.accessToken}`);&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   // 認証状態の確認&lt;br /&gt;
   isAuthenticated(): boolean {&lt;br /&gt;
     return this.tokens !== null;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== 並列リクエスト ====&lt;br /&gt;
複数のAPIエンドポイントから並列でデータを取得する定義例を示す。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
 // api/parallelRequests.ts&lt;br /&gt;
 import { fetch } from &amp;#039;@tauri-apps/plugin-http&amp;#039;;&lt;br /&gt;
 &lt;br /&gt;
 interface DashboardData {&lt;br /&gt;
   user: User;&lt;br /&gt;
   posts: Post[];&lt;br /&gt;
   notifications: Notification[];&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 interface User {&lt;br /&gt;
   id: number;&lt;br /&gt;
   name: string;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 interface Post {&lt;br /&gt;
   id: number;&lt;br /&gt;
   title: string;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 interface Notification {&lt;br /&gt;
   id: number;&lt;br /&gt;
   message: string;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 // 並列リクエストでダッシュボードデータを取得&lt;br /&gt;
 export async function fetchDashboardData(userId: number): Promise&amp;lt;DashboardData&amp;gt; {&lt;br /&gt;
   const baseUrl = &amp;#039;https://jsonplaceholder.typicode.com&amp;#039;;&lt;br /&gt;
 &lt;br /&gt;
   // Promise.allで並列実行&lt;br /&gt;
   const [userResponse, postsResponse, notificationsResponse] = await Promise.all([&lt;br /&gt;
     fetch(`${baseUrl}/users/${userId}`),&lt;br /&gt;
     fetch(`${baseUrl}/posts?userId=${userId}`),&lt;br /&gt;
     fetch(`${baseUrl}/comments?postId=1`), // 代用としてcommentsを使用&lt;br /&gt;
   ]);&lt;br /&gt;
 &lt;br /&gt;
   // 全てのレスポンスをチェック&lt;br /&gt;
   if (!userResponse.ok || !postsResponse.ok || !notificationsResponse.ok) {&lt;br /&gt;
     throw new Error(&amp;#039;Failed to fetch dashboard data&amp;#039;);&lt;br /&gt;
   }&lt;br /&gt;
 &lt;br /&gt;
   // JSONパースも並列で実行&lt;br /&gt;
   const [user, posts, notifications] = await Promise.all([&lt;br /&gt;
     userResponse.json() as Promise&amp;lt;User&amp;gt;,&lt;br /&gt;
     postsResponse.json() as Promise&amp;lt;Post[]&amp;gt;,&lt;br /&gt;
     notificationsResponse.json() as Promise&amp;lt;Notification[]&amp;gt;,&lt;br /&gt;
   ]);&lt;br /&gt;
 &lt;br /&gt;
   return { user, posts, notifications: notifications.slice(0, 5) };&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 // Reactコンポーネントでの使用例&lt;br /&gt;
 import { useState, useEffect } from &amp;#039;react&amp;#039;;&lt;br /&gt;
 &lt;br /&gt;
 function Dashboard({ userId }: { userId: number }) {&lt;br /&gt;
   const [data, setData] = useState&amp;lt;DashboardData | null&amp;gt;(null);&lt;br /&gt;
   const [loading, setLoading] = useState(true);&lt;br /&gt;
 &lt;br /&gt;
   useEffect(() =&amp;gt; {&lt;br /&gt;
     fetchDashboardData(userId)&lt;br /&gt;
       .then(setData)&lt;br /&gt;
       .catch(console.error)&lt;br /&gt;
       .finally(() =&amp;gt; setLoading(false));&lt;br /&gt;
   }, [userId]);&lt;br /&gt;
 &lt;br /&gt;
   if (loading) return &amp;lt;div&amp;gt;Loading dashboard...&amp;lt;/div&amp;gt;;&lt;br /&gt;
 &lt;br /&gt;
   return (&lt;br /&gt;
     &amp;lt;div&amp;gt;&lt;br /&gt;
       &amp;lt;h1&amp;gt;Welcome, {data?.user.name}&amp;lt;/h1&amp;gt;&lt;br /&gt;
       &amp;lt;h2&amp;gt;Recent Posts ({data?.posts.length})&amp;lt;/h2&amp;gt;&lt;br /&gt;
       &amp;lt;h2&amp;gt;Notifications ({data?.notifications.length})&amp;lt;/h2&amp;gt;&lt;br /&gt;
     &amp;lt;/div&amp;gt;&lt;br /&gt;
   );&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== トラブルシューティング ==&lt;br /&gt;
==== URLスコープエラー ====&lt;br /&gt;
&amp;lt;u&amp;gt;URL not allowed&amp;lt;/u&amp;gt; エラーが発生する場合、Capabilities設定を確認する。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
 # エラーメッセージ例&lt;br /&gt;
 Error: URL &amp;quot;https://api.example.com/data&amp;quot; is not allowed&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
* 対処法&lt;br /&gt;
*# &amp;lt;u&amp;gt;src-tauri/capabilities/default.json&amp;lt;/u&amp;gt; ファイルを開く。&lt;br /&gt;
*# &amp;lt;code&amp;gt;http:default&amp;lt;/code&amp;gt; の &amp;lt;code&amp;gt;allow&amp;lt;/code&amp;gt; 配列に対象URLを追加する。&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== ネットワークエラー ====&lt;br /&gt;
ネットワーク接続エラーが発生する場合のチェックリストを示す。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
* インターネット接続の確認&lt;br /&gt;
*: 他のアプリケーションでネットワークが使用できるか確認する。&lt;br /&gt;
* ファイアウォール設定の確認&lt;br /&gt;
*: Tauriアプリがファイアウォールでブロックされていないか確認する。&lt;br /&gt;
* プロキシ設定の確認&lt;br /&gt;
*: 企業ネットワーク等でプロキシが必要な場合は設定を確認する。&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
==== JSONパースエラー ====&lt;br /&gt;
&amp;lt;u&amp;gt;Unexpected token&amp;lt;/u&amp;gt; エラーが発生する場合、レスポンスの形式を確認する。&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;typescript&amp;quot;&amp;gt;&lt;br /&gt;
 // デバッグ用 : レスポンスの内容を確認&lt;br /&gt;
 const response = await fetch(url);&lt;br /&gt;
 const text = await response.text();&lt;br /&gt;
 console.log(&amp;#039;Raw response:&amp;#039;, text);&lt;br /&gt;
 &lt;br /&gt;
 try {&lt;br /&gt;
   const json = JSON.parse(text);&lt;br /&gt;
   console.log(&amp;#039;Parsed JSON:&amp;#039;, json);&lt;br /&gt;
 }&lt;br /&gt;
 catch (e) {&lt;br /&gt;
   console.error(&amp;#039;JSON parse error:&amp;#039;, e);&lt;br /&gt;
 }&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 関連情報 ==&lt;br /&gt;
* [https://v2.tauri.app/plugin/http/ Tauri公式ドキュメント - HTTP Plugin]&lt;br /&gt;
* [https://github.com/tauri-apps/tauri-plugin-http GitHub - tauri-plugin-http]&lt;br /&gt;
* [[Tauriの基礎 - プラグインシステム]]&lt;br /&gt;
* [[Tauriの基礎 - ストア]]&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki&lt;br /&gt;
|keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Tauri,HTTP,fetch,API,TypeScript,React,Rust,Plugin,CORS&lt;br /&gt;
|description={{PAGENAME}} - Tauri v2のHTTPプラグインの使い方、インストール、設定、fetch APIの使用方法について | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux&lt;br /&gt;
|image=/resources/assets/MochiuLogo_Single_Blue.png&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
__FORCETOC__&lt;br /&gt;
[[カテゴリ:Rust]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
</feed>