---
title: マルチプレイサーバーからのHTTPリクエスト
slug: world-sdk-guide-ja/http
docTags: 
createdAt: 2024-09-02T08:34:13.135Z
---

ZEPETO World MultiplayサーバーからHTTPリクエストを行うには、ZEPETO.Multiplay.HttpServiceモジュールを使用します。外部ウェブサービスをビジネスロジックの操作、データストレージ、統計分析、エラートラッキングなどに統合してください。



:::hint{type="danger"}
- HTTPSプロトコルのみを使用することを確認してください。HTTPは開発環境でのみサポートされています。
- リクエストはポート80および443でのみ許可されます。
- リクエストおよびレスポンスボディの最大サイズは16KBに制限されています。
- 過剰なリクエストが発生した場合、世界サービスに制限がかかる可能性があるため、1分あたりのリクエスト数を500未満に保ってください。
- 外部ウェブサービスが5秒以内に応答しない場合、リクエストは失敗します。
- レスポンスヘッダーのcontent-typeが、`HttpContentType`列挙型で定義された値と一致することを確認してください。そうでない場合、リクエストは失敗します。
- さまざまな理由でウェブリクエストが失敗する可能性があるため、防御的にコーディングすることをお勧めします。
:::



## ZEPETO.Multiplay.HttpService

:::hint{type="info"}
**📘&#x20;**&#x6B21;のガイドを参照してください。 \[[ZEPETO.Multiplay.HttpService API](https://developer.zepeto.me/docs/multiplay-server/interfaces/ZEPETO_Multiplay_HttpService.HttpService)]
:::



### メソッド

| **方法**                                                                                                                  | **説明**                                                                                                                                                                                                                                                                                                                                                                                        |
| ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| HttpService.getAsync(url: string, headers?: HttpHeader): Promise                                                        | HTTP GETリクエストを非同期に実行します。<br />**\[パラメータ]**<br />- url : リクエストを送信するウェブアドレス。<br />- headers : HTTPリクエストヘッダー。（オプション）<br /><br />**\[戻り値]**<br />- Promise\<HttpResponse> : 応答に関する情報を含むHttpResponseオブジェクトをPromiseとして返します。                                                                                                                                                                         |
| HttpService.postAsync(url: string, body: HttpBodyType, headers?: HttpHeader): Promise                                   | HTTP POSTリクエストを非同期に実行します。<br />**\[パラメータ]**<br />- url : リクエストを送信するウェブアドレス。<br />- body : リクエストボディの内容。<br />- headers : HTTPリクエストヘッダー。（オプション）<br /><br />**\[戻り値]**<br />- Promise\<HttpResponse> : 応答に関する情報を含むHttpResponseオブジェクトをPromiseとして返します。                                                                                                                                             |
| HttpService.postAsync(url: string, body: HttpBodyType, httpContentType: HttpContentType, headers?: HttpHeader): Promise | HTTP POSTリクエストを非同期に実行します。<br />**\[パラメータ]**<br />- url : リクエストを送信するウェブアドレス。<br />- body : リクエストボディの内容。<br />- httpContentType : リクエストのContent-Typeヘッダーを指定します。<br />- headers : HTTPリクエストヘッダー。（オプション）<br /><br />**\[戻り値]**<br />- Promise\<HttpResponse> : 応答に関する情報を含むHttpResponseオブジェクトをPromiseとして返します。<br /><br />このシグネチャを使用する場合、'Content-Type'をヘッダーに追加すると、httpContentTypeで指定された内容に上書きされます。 |

### その他の宣言

| **宣言**          | **説明**                                                                                                                                                                                                                                                      |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| HttpContentType | HTTPヘッダーのContent-Typeを指定する定数の列挙。<br /><br />- ApplicationJson : 'application/json'<br />- ApplicationXml : 'application/xml'<br />- ApplicationUrlEncoded : 'application/x-www-form-urlencoded'<br />- TextPlain : 'text/plain'<br />- TextXml : 'text/xml' |
| HttpBodyType    | HTTPリクエストボディのコンテンツタイプで、文字列または文字列キーと任意の値を持つオブジェクトのいずれかです。                                                                                                                                                                                                    |
| HttpHeader      | HTTPリクエストヘッダーを定義するためのタイプで、プロパティ値はオブジェクト内の文字列または数値のいずれかです。                                                                                                                                                                                                   |
| HttpResponse    | HTTPリクエストの結果と応答データに関する情報を含むインターフェース。<br /><br />- statusCodeHTTP : 応答のステータスコードを表す数値。通常、200は成功したリクエストを示します。<br />- statusTextHTTP : 応答のステータスメッセージを表す文字列。通常、「OK」は成功したリクエストを示します。<br />- response : HTTP応答ボディデータを含む文字列。                                        |

:::hint{type="info"}
**📘 HTTPステータス**
[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)
:::



## コードサンプル

### 基本的なGETリクエスト

シンプルなGETリクエストの例を作成しましょう。`HttpService.getAsync`. 新しいクライアントがMultiplay Roomに接続すると、外部ウェブサービスにHTTPリクエストを送信し、結果をログに記録します。

[restcountries.com](https://restcountries.com/) は、さまざまな国に関する情報を提供するオープンAPIです。このサービスを使用して、日本の首都を調べます。

Multiplayを設定し、次にWorld.multiplay/index.tsを開いて、サーバースクリプトを次のように記述します。

:::hint{type="info"}
**📘&#x20;**&#x6B21;のガイドを参照してください。 \[[マルチプレイ](docId:0rsOGFDZraxefYEx5jVA6)]
:::



```typescript
import { Sandbox, SandboxOptions, SandboxPlayer } from "ZEPETO.Multiplay";
import { HttpService } from "ZEPETO.Multiplay.HttpService";

export default class extends Sandbox {

    onCreate(options: SandboxOptions) { }
    onJoin(client: SandboxPlayer) { this.findCapitalCity() }
    onLeave(client: SandboxPlayer, consented?: boolean) { }

    findCapitalCity() {
        // Make the request to the restcountries API
        HttpService.getAsync("https://restcountries.com/v3.1/name/japan?fields=capital")
            // Handler for the HTTP Response   
            .then((httpResponse) => {
                // Parse the JSON response data from the API (which is nested in HTTP Response)
                let countries = JSON.parse(httpResponse.response);
                console.log("日本の首都は:");
                console.log(`${countries[0].capital}`);
            });
    }
}
```

コードの説明：

- クライアントがマルチプレイルームに接続すると、`onJoin`関数がトリガーされ、`findCapitalCity`が呼び出されます。
- もし、`getAsync`がrestcountries APIに成功した場合、`httpResponse`オブジェクトにアクセスできます。`then`コールバック内で。
- APIレスポンスを解析して、`httpResponse.response`をJSON形式からオブジェクトに変換します。
- APIレスポンスの構造を参照することで、必要なプロパティにアクセスし、その値を印刷します。

Unityエディタでマルチプレイサーバーを実行し、シーンを再生すると、コンソールに次の内容が表示されます。

```text
日本の首都は:
東京
```

### 防御的コーディングプラクティス

- 一方、導入の注意事項で述べたように、ウェブリクエストは、ウェブアドレスやAPIレスポンス形式の変更など、さまざまな理由で失敗する可能性があります。
- これらのリクエストを適切に処理しないと、World playにさまざまな悪影響を及ぼす可能性があるため、特にHTTPリクエストを扱う際には防御的にコーディングすることをお勧めします。
- 以下は、上記のコードにいくつかの防御的コーディング技術を適用する例です。

```typescript
   findCapitalCity() {
    // restcountries APIへのリクエストを行う
    HttpService.getAsync(
        "https://restcountries.com/v3.1/name/japan?fields=capital",
        { 'Accept': HttpContentType.ApplicationJson })
        // HTTPレスポンスのハンドラー
        .then((httpResponse) => {
            // APIコールが200(OK)を返したかどうかを確認
            if (httpResponse.statusCode != 200) {
                // 200(OK)でない場合は、処理を続けずカスタムエラーを発生させる
                throw (`APIエラー: ${httpResponse.statusCode} ${httpResponse.statusText}`);
            }
            // APIからのJSONレスポンスデータを返す
            return httpResponse.response;
        })
        // APIからのJSONレスポンスデータのハンドラー
        .then((response) => {
            // JSONレスポンスデータを解析
            let countries = JSON.parse(response);
            // APIレスポンスデータが有効かどうかを確認
            if (!Array.isArray(countries) || !countries.length) {
                // 配列でない場合、または空の場合
                // 処理を続けずカスタムエラーを発生させる
                throw (`APIエラー: レスポンスデータが無効です`);
            }
            let country = countries[0];
            // 'capital'フィールドが有効かどうかを確認
            if (!country.capital) {
                // 'capital'フィールドが存在しない、または空の場合
                // 処理を続けずカスタムエラーを発生させる
                throw (`APIエラー: 'capital'フィールドが無効です`);
            }
            console.log("日本の首都は:")
            console.log(`${country.capital}`);
        })
        // getAsync呼び出しと'then'句で発生するエラーのハンドラー。
        .catch((reason) => {
            console.log("APIリクエストエラー");
            console.log(reason);
        });
}
```

ここで適用される防御的コーディング技術には、以下が含まれます：

- 使用する `Accept` ヘッダー： `Accept` ヘッダーは、レスポンスボディの期待されるContent-Typeを指定するために使用されます。サーバーによっては、レスポンスのContent-Typeは `Accept` ヘッダーに基づいて調整されることがあります。
- チェックする `HttpResponse.statusCode`: `HttpResponse.statusCode` プロパティは、リクエストの成功を確認するために使用されます。
- JSONデータ構造の検証： `JSON.parse` を使用して解析されたオブジェクトのデータ構造が期待される構造と一致するか確認します。
- プロパティの存在確認：使用する予定のプロパティがオブジェクトに実際に存在することを確認します。
- Promiseの `catch` メソッドを利用する：Promiseの `catch` メソッドは、APIリクエストやレスポンス処理中に発生する可能性のあるエラーを処理するために使用されます。

これらの技術は、予期しないエラーに直面してもコードが信頼性を持って動作するように保護し、その堅牢性を高めます。



### クライアントとの統合：ルームメッセージを介して

HTTPリクエストは、Multiplayサーバーからのみ可能です。

しかし、Multiplayルームメッセージを使用することで、クライアントから外部ウェブサービスにHTTPリクエストを送信するようサーバーをトリガーし、クライアント内でその応答を利用することができます。

以下の例は、クライアントとサーバーの統合を示しています。このデモでは、クライアントのUI上のボタンが押されると、そのボタンに対応する国の首都が表示されます。

:::hint{type="info"}
**📘&#x20;**&#x4EE5;下のガイドを参照してください。 \[[Multiplay Room Message](docId\:P_hrMrcYw91bz52ji7W67)]
:::



![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-tfcubL3eArDSHrPB-D9AO-20240904-102411.gif)



**クライアントコード**

```typescript
import { ZepetoScriptBehaviour } from 'ZEPETO.Script'
import { Room } from 'ZEPETO.Multiplay'
import { ZepetoWorldMultiplay } from 'ZEPETO.World';
import { Button, Text } from 'UnityEngine.UI'

export default class SampleScript extends ZepetoScriptBehaviour {

    public multiplay: ZepetoWorldMultiplay;
    public room: Room;
    public countryButtons: Button[];
    public capitalText: Text;


    Start() {
        interface Response {
            capitals: string[]
        }

        for (const countryButton of this.countryButtons) {
            countryButton.onClick.AddListener(() => {
                if (this.room !== null) {
                    // 国名を 'client-to-server' タイプのメッセージとしてサーバーに送信
                    this.room.Send("client-to-server", countryButton.GetComponentInChildren<Text>().text);
                }
            });
        };

        this.multiplay.RoomCreated += (room: Room) => {
            this.room = room;
            // 'server-to-client' タイプのメッセージを受信したときの処理
            this.room.AddMessageHandler("server-to-client", (message: Response) => {
                // 複数の首都がある国の場合、
                // 文字列要素を ', ' で結合してシーンに表示
                this.capitalText.text = message.capitals.join(", ");
            });
        };
    }
}
```

コードの説明：

- 国名を表示するボタンを反復処理するリスナーを定義します。クリックされると、このリスナーはマルチプレイサーバーにルームメッセージを送信します。
- このリスナーは、ボタンに表示されている国名を 'client-to-server' タイプのメッセージとして送信します。
- 応答を処理するために、'server-to-client' タイプのルームメッセージを受信するためのリスナーも定義します。
- このリスナーは、サーバーから受信した首都名を画面に表示します。複数の首都がある場合は、画面にカンマで区切って表示されます。



**サーバーコード**

```typescript
import { Sandbox, SandboxOptions, SandboxPlayer } from "ZEPETO.Multiplay";
import { HttpService } from "ZEPETO.Multiplay.HttpService";

export default class extends Sandbox {

    onCreate(options: SandboxOptions) {
        // 'client-to-server'タイプのメッセージを受信したときの処理
        this.onMessage("client-to-server", (client, message) => {
            console.log(`クライアント ${client.userId} がリクエストを送信しました。メッセージ: ${message}`);
            this.findCapitalCity(message, client);
        });
    }

    onJoin(client: SandboxPlayer) { }
    onLeave(client: SandboxPlayer, consented?: boolean) { }

    findCapitalCity(countryName: string, client: SandboxPlayer) {
        // countryNameをパスパラメータとしてAPIにリクエスト
        // countryNameはクライアントからルームメッセージとして送信される
        HttpService.getAsync(`https://restcountries.com/v3.1/name/${countryName}?fields=capital`)
            .then((httpResponse) => {
                if (httpResponse.statusCode != 200) {
                    throw (`APIエラー: ${httpResponse.statusCode} ${httpResponse.statusText}`);
                }
                return httpResponse.response;
            })
            .then((response) => {
                let countries = JSON.parse(response);
                if (!Array.isArray(countries) || !countries.length) {
                    throw (`APIエラー: レスポンスデータが無効です`);
                }
                let country = countries[0];
                if (!country.capital) {
                    throw (`APIエラー: 'capital'フィールドが無効です`);
                }
                // クライアントに'server-to-client'タイプのメッセージを送信
                // メッセージは首都名を含むオブジェクトです
                client.send("server-to-client", {
                    "capitals": country.capital
                });
            })
            .catch((reason) => {
                console.log("APIリクエストエラー");
                console.log(reason);
            });
    }
}
```

コードの説明:

- クライアントからサーバーへのタイプのマルチプレイルームメッセージを受信したときに呼び出すリスナーを定義します。`findCapitalCity`。
- 国名を使用してマルチプレイルームメッセージのアドレスを構築し、`getAsync`呼び出しを行います。
- 呼び出しが成功した場合、応答は以前の例と同様に処理されます。
- restcountries APIの応答から取得した首都名は、サーバーからクライアントへのタイプのルームメッセージとしてクライアントに送信されます。



### POSTリクエスト

最後に、`HttpService.postAsync`を使用してPOSTリクエストの例を作成しましょう。

[postman-echo](https://postman-echo.com/)は、ウェブリクエストから受信したコンテンツを示す構造化された応答を提供するサービスであり、クライアントがリクエストを正しく構成しているかを確認するのに効果的です。

この例を通じて、クエリパラメータ、リクエストボディ、およびヘッダーを持つPOSTリクエストを設定し、リクエストが適切に構成されていることを確認します。

Multiplayを設定し、次にWorld.multiplay/index.tsを開いて、サーバースクリプトを以下のように記述します。

```typescript
import { Sandbox, SandboxOptions, SandboxPlayer } from "ZEPETO.Multiplay";
import { HttpContentType, HttpService } from "ZEPETO.Multiplay.HttpService";

export default class extends Sandbox {

    onCreate(options: SandboxOptions) { }
    onJoin(client: SandboxPlayer) { this.echoPost() }
    onLeave(client: SandboxPlayer, consented?: boolean) { }

    echoPost() {
        HttpService.postAsync(
            // APIエンドポイントとクエリパラメータ
            "https://postman-echo.com/post?argKey=argValue",
            // JSONリクエストボディ
            { "dataKey": "dataValue" },
            // リクエストコンテンツタイプ
            HttpContentType.ApplicationJson,
            // HTTPヘッダー
            { "header-key": "header-value" })
            .then((httpResponse) => {
                if (httpResponse.statusCode != 200) {
                    throw (`APIエラー: ${httpResponse.statusCode} ${httpResponse.statusText}`);
                }
                return httpResponse.response;
            })
            .then((response) => {
                let parsed = JSON.parse(response);
                console.log(`クエリパラメータ: argKey:${parsed.args.argKey}`);
                console.log(`リクエストボディ: dataKey:${parsed.data.dataKey}`);
                console.log(`リクエストヘッダー: header-key:${parsed.headers["header-key"]}`)
            })
            .catch((reason) => {
                console.log("APIリクエストエラー");
                console.log(reason);
            });
    }
}
```

コードの説明：

- クライアントがマルチプレイルームに接続すると、`echoPost`関数が`onJoin`トリガーから呼び出されます。
- 次の`postAsync`リクエストを作成する際：
  - 最初のパラメータでは、クエリパラメータを含むURL文字列を構築します。
  - 2番目のパラメータでは、リクエストボディの内容を設定します。
  - 4番目のパラメータでは、リクエストヘッダーを設定します。
  - リクエストボディがJSON形式であることを指定するために、3番目のパラメータに'application/json' Content-Typeを設定します。
- もし`postAsync`呼び出しが成功した場合、`httpResponse`オブジェクトにアクセスできます。`その後`コールバック。
- 私たちは`httpResponse.response`を解析して、APIのレスポンスをJSON形式からオブジェクトに変換します。
- APIレスポンスの構造を参照し、コンソール出力を使用して、HTTPリクエストのクエリパラメータ、リクエストボディ、およびリクエストヘッダーが正しく設定されているかを確認します。

UnityエディタでMultiplayサーバーを実行し、シーンを再生すると、コンソールに以下が表示されます。

```text
クエリパラメータ: argKey:argValue
リクエストボディ: dataKey:dataValue
リクエストヘッダー: header-key:header-value
```

