Laravel 9.x HTTPクライアント

イントロダクション

Laravelは、Guzzle HTTPクライアントの周りに表現力豊かで最小限のAPIを提供し、他のWebアプリケーションと通信するための外部HTTPリクエストをすばやく作成できるようにします。LaravelによるGuzzleのラッパーは、最も一般的なユースケースと素晴らしい開発者エクスペリエンスに焦点を当てています。

使い始める前に、アプリケーションの依存関係としてGuzzleパッケージを確実にインストールしてください。デフォルトでLaravelはこの依存パッケージを自動的に含めます。もし、以前にパッケージを削除したことがある場合は、Composerを介して再度インストールしてください。

composer require guzzlehttp/guzzle

リクエストの作成

リクエストを行うには、Httpファサードが提供するheadgetpostputpatchdeleteメソッドを使用します。まず、外部のURLに対して基本的なGETリクエストを行う方法を見てみましょう。

use Illuminate\Support\Facades\Http;

$response = Http::get('http://example.com');

getメソッドはIlluminate\Http\Client\Responseのインスタンスを返します。これは、レスポンスを調べるために使用できるさまざまなメソッドを提供します。

$response->body() : string;
$response->json($key = null, $default = null) : array|mixed;
$response->object() : object;
$response->collect($key = null) : Illuminate\Support\Collection;
$response->status() : int;
$response->successful() : bool;
$response->redirect(): bool;
$response->failed() : bool;
$response->clientError() : bool;
$response->header($header) : string;
$response->headers() : array;

Illuminate\Http\Client\ResponseオブジェクトはPHPのArrayAccessインターフェイスも実装しており、そのレスポンスのJSONレスポンスデータへ直接アクセスできます。

return Http::get('http://example.com/users/1')['name'];

上記レスポンスメソッドに加え、以下のメソッドにより、レスポンスが特定のステータスコードを持つか判断できます。

$response->ok() : bool;                  // 200 OK
$response->created() : bool;             // 201 Created
$response->accepted() : bool;            // 202 Accepted
$response->noContent() : bool;           // 204 No Content
$response->movedPermanently() : bool;    // 301 Moved Permanently
$response->found() : bool;               // 302 Found
$response->badRequest() : bool;          // 400 Bad Request
$response->unauthorized() : bool;        // 401 Unauthorized
$response->paymentRequired() : bool;     // 402 Payment Required
$response->forbidden() : bool;           // 403 Forbidden
$response->notFound() : bool;            // 404 Not Found
$response->requestTimeout() : bool;      // 408 Request Timeout
$response->conflict() : bool;            // 409 Conflict
$response->unprocessableEntity() : bool; // 422 Unprocessable Entity
$response->tooManyRequests() : bool;     // 429 Too Many Requests
$response->serverError() : bool;         // 500 Internal Server Error

URIテンプレート

HTTPクライアントは、URIテンプレート仕様を用いて、リクエストURLを構築することも可能です。URIテンプレートで展開できるURLパラメータを定義するには、withUrlParametersメソッドを使用します。

Http::withUrlParameters([
    'endpoint' => 'https://laravel.com',
    'page' => 'docs',
    'version' => '9.x',
    'topic' => 'validation',
])->get('{+endpoint}/{page}/{version}/{topic}');

リクエストのダンプ

送信するリクエストインスタンスを送信して、スクリプトの実行を終了する前にダンプしたい場合は、リクエスト定義の先頭にddメソッドを追加できます。

return Http::dd()->get('http://example.com');

リクエストデータ

もちろん、POSTPUTPATCHリクエストを作成するときは、リクエストとともに追加のデータを送信するのが一般的であるため、これらのメソッドは2番目の引数としてデータの配列を受け入れます。デフォルトでデータはapplication/jsonコンテンツタイプを使用して送信されます。

use Illuminate\Support\Facades\Http;

$response = Http::post('http://example.com/users', [
    'name' => 'Steve',
    'role' => 'Network Administrator',
]);

GETリクエストクエリパラメータ

GETリクエストを行うときは、クエリ文字列をURLに直接追加するか、キー/値ペアの配列をgetメソッドの2番目の引数として渡せます。

$response = Http::get('http://example.com/users', [
    'name' => 'Taylor',
    'page' => 1,
]);

フォームURLエンコードされたリクエストの送信

application/x-www-form-urlencodedコンテンツタイプを使用してデータを送信する場合は、リクエストを行う前にasFormメソッドを呼び出す必要があります。

$response = Http::asForm()->post('http://example.com/users', [
    'name' => 'Sara',
    'role' => 'Privacy Consultant',
]);

素のリクエスト本文の送信

リクエストを行うときに素のリクエスト本文を指定する場合は、withBodyメソッドを使用できます。コンテンツタイプは、メソッドの2番目の引数を介して提供できます。

$response = Http::withBody(
    base64_encode($photo), 'image/jpeg'
)->post('http://example.com/photo');

マルチパートリクエスト

ファイルをマルチパートリクエストとして送信する場合は、リクエストを行う前にattachメソッドを呼び出す必要があります。このメソッドは、ファイルの名前とその内容を引数に取ります。必要に応じて、ファイルのファイル名と見なす3番目の引数を指定できます。

$response = Http::attach(
    'attachment', file_get_contents('photo.jpg'), 'photo.jpg'
)->post('http://example.com/attachments');

ファイルの素の内容を渡す代わりに、ストリームリソースを渡すこともできます。

$photo = fopen('photo.jpg', 'r');

$response = Http::attach(
    'attachment', $photo, 'photo.jpg'
)->post('http://example.com/attachments');

ヘッダ

ヘッダは、withHeadersメソッドを使用してリクエストに追加できます。このwithHeadersメソッドは、キー/値ペアの配列を引数に取ります。

$response = Http::withHeaders([
    'X-First' => 'foo',
    'X-Second' => 'bar'
])->post('http://example.com/users', [
    'name' => 'Taylor',
]);

acceptメソッドを使って、アプリケーションがリクエストへのレスポンスとして期待するコンテンツタイプを指定できます。

$response = Http::accept('application/json')->get('http://example.com/users');

利便性のため、acceptJsonメソッドを使って、アプリケーションがリクエストへのレスポンスとしてapplication/jsonコンテンツタイプを期待することを素早く指定できます。

$response = Http::acceptJson()->get('http://example.com/users');

認証

基本認証のログイン情報とダイジェスト認証ログイン情報は、それぞれwithBasicAuthメソッドとwithDigestAuthメソッドを使用して指定します。

// BASIC認証
$response = Http::withBasicAuth('taylor@laravel.com', 'secret')->post(/* ... */);

// ダイジェスト認証
$response = Http::withDigestAuth('taylor@laravel.com', 'secret')->post(/* ... */);

Bearerトークン

リクエストのAuthorizationヘッダにBearerトークンをすばやく追加したい場合は、withTokenメソッドを使用できます。

$response = Http::withToken('token')->post(/* ... */);

タイムアウト

timeoutメソッドを使用して、レスポンスを待機する最大秒数を指定できます。

$response = Http::timeout(3)->get(/* ... */);

指定したタイムアウトを超えると、Illuminate\Http\Client\ConnectionExceptionインスタンスを投げます。

サーバへの接続を試みる最長待ち秒数をconnectTimeoutメソッドで指定できます。

$response = Http::connectTimeout(3)->get(/* ... */);

再試行

クライアントまたはサーバのエラーが発生した場合に、HTTPクライアントがリクエストを自動的に再試行するようにしたい場合は、retryメソッドを使用します。retryメソッドは、リクエストを試行する最大回数とLaravelが試行の間に待機するミリ秒数を引数に取ります。

$response = Http::retry(3, 100)->post(/* ... */);

必要であれば、retryメソッドに第3引数を渡せます。第3引数には、実際に再試行を行うかどうかを決定するCallableを指定します。例えば、最初のリクエストでConnectionExceptionが発生した場合にのみ、リクエストを再試行したいとしましょう。

$response = Http::retry(3, 100, function ($exception, $request) {
    return $exception instanceof ConnectionException;
})->post(/* ... */);

リクエストの試行に失敗した場合、新しく試みる前にリクエストへ変更を加えたい場合があります。これを実現するには、retryメソッドに渡すコールバックのrequest引数を変更します。例えば、最初の試行が認証エラーを返した場合、新しい認証トークンを使ってリクエストを再試行したいと思います。

$response = Http::withToken($this->getToken())->retry(2, 0, function ($exception, $request) {
    if (! $exception instanceof RequestException || $exception->response->status() !== 401) {
        return false;
    }

    $request->withToken($this->getNewToken());

    return true;
})->post(/* ... */);

すべてのリクエストが失敗した場合、 Illuminate\Http\Client\RequestExceptionインスタンスを投げます。この動作を無効にする場合は、throw引数へfalseを指定してください。無効にすると、すべての再試行のあと、クライアントが最後に受信したレスポンスを返します。

$response = Http::retry(3, 100, throw: false)->post(/* ... */);

Warning!! 接続の問題ですべてのリクエストが失敗した場合は、throw引数をfalseに設定していてもIlluminate\Http\Client\ConnectionExceptionが投げられます。

エラー処理

Guzzleのデフォルト動作とは異なり、LaravelのHTTPクライアントラッパーは、クライアントまたはサーバのエラー(サーバからの「400」および「500」レベルの応答)で例外を投げません。successfulclientErrorserverErrorメソッドを使用して、これらのエラーのいずれかが返されたかどうかを判定できます。

// ステータスコードが200以上300未満か判定
$response->successful();

// ステータスコードが400以上か判定
$response->failed();

// レスポンスに400レベルのステータスコードがあるかを判定
$response->clientError();

// レスポンスに500レベルのステータスコードがあるかを判定
$response->serverError();

// クライアントまたはサーバエラーが発生した場合、指定コールバックを即座に実行
$response->onError(callable $callback);

例外を投げる

あるレスポンスインスタンスのレスポンスステータスコードがクライアントまたはサーバのエラーを示している場合にIlluminate\Http\Client\RequestExceptionのインスタンスを投げたい場合場合は、throwthrowIfメソッドを使用します。

$response = Http::post(/* ... */);

// クライアントまたはサーバのエラーが発生した場合は、例外を投げる
$response->throw();

// エラーが発生し、指定条件が真の場合は、例外を投げる
$response->throwIf($condition);

// エラーが発生し、指定クロージャの結果が真の場合は例外を投げる
$response->throwIf(fn ($response) => true);

// エラーが発生し、指定条件が偽の場合は、例外を投げる
$response->throwUnless($condition);

// エラーが発生し、指定クロージャの結果が偽の場合は例外を投げる
$response->throwUnless(fn ($response) => false);

// レスポンスが特定のステータスコードの場合は、例外を投げる
$response->throwIfStatus(403);

// レスポンスが特定のステータスコードでない場合は、例外を投げる
$response->throwUnlessStatus(200);

return $response['user']['id'];

Illuminate\Http\Client\RequestExceptionインスタンスにはパブリック$responseプロパティがあり、返ってきたレスポンスを検査できます。

throwメソッドは、エラーが発生しなかった場合にレスポンスインスタンスを返すので、他の操作をthrowメソッドにチェーンできます。

return Http::post(/* ... */)->throw()->json();

例外がなげられる前に追加のロジックを実行したい場合は、throwメソッドにクロージャを渡せます。クロージャを呼び出した後に、例外を自動的に投げるため、クロージャ内から例外を再発行する必要はありません。

return Http::post(/* ... */)->throw(function ($response, $e) {
    //
})->json();

Guzzleミドルウェア

LaravelのHTTPクライアントはGuzzleで動いているので、Guzzleミドルウェアを利用して、送信するリクエストの操作や受信したレスポンスの検査ができます。送信リクエストを操作するには、withMiddlewareメソッドとGuzzleのmapRequestミドルウェアファクトリを組み合わせて、Guzzleミドルウェアを登録します。

use GuzzleHttp\Middleware;
use Illuminate\Support\Facades\Http;
use Psr\Http\Message\RequestInterface;

$response = Http::withMiddleware(
    Middleware::mapRequest(function (RequestInterface $request) {
        $request = $request->withHeader('X-Example', 'Value');

        return $request;
    })
)->get('http://example.com');

同様に、GuzzleのmapResponseミドルウェアファクトリと組み合わせてwithMiddlewareメソッドをを登録すれば、受信HTTPレスポンスを検査できます。

use GuzzleHttp\Middleware;
use Illuminate\Support\Facades\Http;
use Psr\Http\Message\ResponseInterface;

$response = Http::withMiddleware(
    Middleware::mapResponse(function (ResponseInterface $response) {
        $header = $response->getHeader('X-Example');

        // ...

        return $response;
    })
)->get('http://example.com');

Guzzleオプション

withOptionsメソッドを使用して、追加のGuzzleリクエストオプションを指定できます。withOptionsメソッドは、キー/値ペアの配列を引数に取ります。

$response = Http::withOptions([
    'debug' => true,
])->get('http://example.com/users');

同時リクエスト

複数のHTTPリクエストを同時に実行したい場合があります。言い換えれば、複数のリクエストを順番に発行するのではなく、同時にディスパッチしたい状況です。これにより、低速なHTTP APIを操作する際のパフォーマンスが大幅に向上します。

さいわいに、poolメソッドを使い、これを実現できます。poolメソッドは、Illuminate\Http\Client\Poolインスタンスを受け取るクロージャを引数に取り、簡単にリクエストプールにリクエストを追加してディスパッチできます。

use Illuminate\Http\Client\Pool;
use Illuminate\Support\Facades\Http;

$responses = Http::pool(fn (Pool $pool) => [
    $pool->get('http://localhost/first'),
    $pool->get('http://localhost/second'),
    $pool->get('http://localhost/third'),
]);

return $responses[0]->ok() &&
       $responses[1]->ok() &&
       $responses[2]->ok();

ご覧のように、各レスポンスインスタンスは、プールに追加した順でアクセスできます。必要に応じasメソッドを使い、リクエストに名前を付けると、対応するレスポンスへ名前でアクセスできるようになります。

use Illuminate\Http\Client\Pool;
use Illuminate\Support\Facades\Http;

$responses = Http::pool(fn (Pool $pool) => [
    $pool->as('first')->get('http://localhost/first'),
    $pool->as('second')->get('http://localhost/second'),
    $pool->as('third')->get('http://localhost/third'),
]);

return $responses['first']->ok();

マクロ

LaravelのHTTPクライアントでは、「マクロ」を定義可能です。マクロは、アプリケーション全体でサービスとやり取りする際に、共通のリクエストパスやヘッダを設定するために、流暢で表現力のあるメカニズムとして機能します。利用するには、アプリケーションの App\Providers\AppServiceProviderクラスのbootメソッド内で、マクロを定義します。

use Illuminate\Support\Facades\Http;

/**
 * 全アプリケーションサービスの初期起動処理
 *
 * @return void
 */
public function boot()
{
    Http::macro('github', function () {
        return Http::withHeaders([
            'X-Example' => 'example',
        ])->baseUrl('https://github.com');
    });
}

マクロを設定したら、アプリケーションのどこからでもマクロを呼び出し、保留中のリクエストを指定した設定で作成できます。

$response = Http::github()->get('/');

テスト

Laravelの多くのサービスでは、テストを簡単かつ表現豊かに書くための機能を提供しており、HTTPクライアントも例外ではありません。Httpファサードのfakeメソッドにより、リクエストが行われたときにスタブ/ダミーレスポンスを返すようにHTTPクライアントに指示できます。

レスポンスのfake

たとえば、リクエストごとに空の200ステータスコードレスポンスを返すようにHTTPクライアントに指示するには、引数なしでfakeメソッドを呼びだしてください。

use Illuminate\Support\Facades\Http;

Http::fake();

$response = Http::post(/* ... */);

特定のURLのfake

もしくは、配列をfakeメソッドに渡すこともできます。配列のキーは、fakeしたいURLパターンとそれに関連するレスポンスを表す必要があります。*文字はワイルドカード文字として使用できます。FakeしないURLに対して行うリクエストは、実際に実行されます。Httpファサードのresponseメソッドを使用して、これらのエンドポイントのスタブ/fakeのレスポンスを作成できます。

Http::fake([
    // GitHubエンドポイントのJSONレスポンスをスタブ
    'github.com/*' => Http::response(['foo' => 'bar'], 200, $headers),

    // Googleエンドポイントの文字列レスポンスをスタブ
    'google.com/*' => Http::response('Hello World', 200, $headers),
]);

一致しないすべてのURLをスタブするフォールバックURLパターンを指定する場合は、単一の*文字を使用します。

Http::fake([
    // GitHubエンドポイントのJSONレスポンスをスタブ
    'github.com/*' => Http::response(['foo' => 'bar'], 200, ['Headers']),

    // 他のすべてのエンドポイントの文字列をスタブ
    '*' => Http::response('Hello World', 200, ['Headers']),
]);

fakeレスポンスの順番

場合によっては、単一のURLが特定の順序で一連のfakeレスポンスを返すように指定する必要があります。これは、Http::sequenceメソッドを使用してレスポンスを作成することで実現できます。

Http::fake([
    // GitHubエンドポイントの一連のレスポンスをスタブ
    'github.com/*' => Http::sequence()
                            ->push('Hello World', 200)
                            ->push(['foo' => 'bar'], 200)
                            ->pushStatus(404),
]);

レスポンスシーケンス内のすべてのレスポンスが消費されると、以降のリクエストに対し、レスポンスシーケンスは例外を投げます。シーケンスが空になったときに返すデフォルトのレスポンスを指定する場合は、whenEmptyメソッドを使用します。

Http::fake([
    // GitHubエンドポイントの一連のレスポンスをスタブ
    'github.com/*' => Http::sequence()
                            ->push('Hello World', 200)
                            ->push(['foo' => 'bar'], 200)
                            ->whenEmpty(Http::response()),
]);

一連のレスポンスをfakeしたいが、fakeする必要がある特定のURLパターンを指定する必要がない場合は、Http::fakeSequenceメソッドを使用します。

Http::fakeSequence()
        ->push('Hello World', 200)
        ->whenEmpty(Http::response());

Fakeコールバック

特定のエンドポイントに対して返すレスポンスを決定するために、より複雑なロジックが必要な場合は、fakeメソッドにクロージャを渡すことができます。このクロージャはIlluminate\Http\Client\Requestインスタンスを受け取り、レスポンスインスタンスを返す必要があります。クロージャ内で、返すレスポンスのタイプを決定するために必要なロジックを実行できます。

use Illuminate\Http\Client\Request;

Http::fake(function (Request $request) {
    return Http::response('Hello World', 200);
});

行き先がないリクエストの防止

HTTPクライアントから送信したすべてのリクエストを個々のテスト、またはテストスイート全体で確実にフェイクにしたい場合は、preventStrayRequestsメソッドをコールします。このメソッドを呼び出すと、対応するフェイクレスポンスがないリクエストは、実際にHTTPリクエストを行うのではなく、例外を投げるようになります。

use Illuminate\Support\Facades\Http;

Http::preventStrayRequests();

Http::fake([
    'github.com/*' => Http::response('ok'),
]);

// "ok"レスポンスが返される
Http::get('https://github.com/laravel/framework');

// 例外が投げられる
Http::get('https://laravel.com');

レスポンスの検査

レスポンスをfakeする場合、アプリケーションが正しいデータまたはヘッダを送信していることを確認するために、クライアントが受信するリクエストを調べたい場合があります。これは、Http::fakeを呼び出した後にHttp::assertSentメソッドを呼び出し実現します。

assertSentメソッドは、Illuminate\Http\Client\Requestインスタンスを受け取るクロージャを引数に受け、リクエストがエクスペクテーションに一致するかを示す論理値を返す必要があります。テストに合格するには、指定するエクスペクテーションに一致する少なくとも1つのリクエストが発行される必要があります。

use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Http;

Http::fake();

Http::withHeaders([
    'X-First' => 'foo',
])->post('http://example.com/users', [
    'name' => 'Taylor',
    'role' => 'Developer',
]);

Http::assertSent(function (Request $request) {
    return $request->hasHeader('X-First', 'foo') &&
           $request->url() == 'http://example.com/users' &&
           $request['name'] == 'Taylor' &&
           $request['role'] == 'Developer';
});

必要に応じて、assertNotSentメソッドを使用して特定のリクエストが送信されないことを宣言できます。

use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Http;

Http::fake();

Http::post('http://example.com/users', [
    'name' => 'Taylor',
    'role' => 'Developer',
]);

Http::assertNotSent(function (Request $request) {
    return $request->url() === 'http://example.com/posts';
});

テスト中にいくつのリクエストを「送信」"したかを宣言するため、assertSentCountメソッドを使用できます。

Http::fake();

Http::assertSentCount(5);

または、assertNothingSentメソッドを使用して、テスト中にリクエストが送信されないことを宣言することもできます。

Http::fake();

Http::assertNothingSent();

リクエスト/レスポンスの記録

すべてのリクエストと、それに対応するレスポンスを収集するために、recordedメソッドが使用できます。recordedメソッドは、Illuminate\Http\Client\RequestIlluminate\Http\Client\Responseインスタンスを含む配列のコレクションを返します。

Http::fake([
    'https://laravel.com' => Http::response(status: 500),
    'https://nova.laravel.com/' => Http::response(),
]);

Http::get('https://laravel.com');
Http::get('https://nova.laravel.com/');

$recorded = Http::recorded();

[$request, $response] = $recorded[0];

さらに、recordedメソッドは、Illuminate\Http\Client\RequestIlluminate\Http\Client\Responseインスタンスを受け取るクロージャを引数に取り、エクスペクテーションに基づいてリクエストとレスポンスのペアをフィルターするために使用できます。

use Illuminate\Http\Client\Request;
use Illuminate\Http\Client\Response;

Http::fake([
    'https://laravel.com' => Http::response(status: 500),
    'https://nova.laravel.com/' => Http::response(),
]);

Http::get('https://laravel.com');
Http::get('https://nova.laravel.com/');

$recorded = Http::recorded(function (Request $request, Response $response) {
    return $request->url() !== 'https://laravel.com' &&
           $response->successful();
});

イベント

LaravelはHTTPリクエストを送信する過程で、3つのイベントを発行します。RequestSendingイベントはリクエストが送信される前に発生し、ResponseReceivedイベントは指定したリクエストに対するレスポンスを受け取った後に発行します。ConnectionFailedイベントは、指定したリクエストに対するレスポンスを受信できなかった場合に発行します。

RequestSendingConnectionFailedイベントは両方とも、パブリックの$requestプロパティを含んでおり、これを使えばIlluminate\Http\Client\Requestインスタンスを調べられます。同様に、ResponseReceivedイベントは、$requestプロパティと$responseプロパティを含んでおり、Illuminate\Http\Client\Responseインスタンスの検査に使用できます。このイベントのイベントリスナは、App\Providers\EventServiceProviderサービスプロバイダで登録します。

/**
 * アプリケーションのイベントリスナマップ
 *
 * @var array
 */
protected $listen = [
    'Illuminate\Http\Client\Events\RequestSending' => [
        'App\Listeners\LogRequestSending',
    ],
    'Illuminate\Http\Client\Events\ResponseReceived' => [
        'App\Listeners\LogResponseReceived',
    ],
    'Illuminate\Http\Client\Events\ConnectionFailed' => [
        'App\Listeners\LogConnectionFailed',
    ],
];

ドキュメント章別ページ

ヘッダー項目移動

注目:アイコン:ページ内リンク設置(リンクがないヘッダーへの移動では、リンクがある以前のヘッダーのハッシュをURLへ付加します。

移動

クリックで即時移動します。

設定

適用ボタンクリック後に、全項目まとめて適用されます。

カラーテーマ
和文指定 Pagination
和文指定 Scaffold
Largeスクリーン表示幅
インデント
本文フォント
コードフォント
フォント適用確認

フォントの指定フィールドから、フォーカスが外れると、当ブロックの内容に反映されます。EnglishのDisplayもPreviewしてください。

フォント設定時、表示に不具合が出た場合、当サイトのクッキーを削除してください。

バックスラッシュを含むインライン\Code\Blockの例です。

以下はコードブロックの例です。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * ユーザに関連する電話レコードを取得
     */
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

設定を保存する前に、表示が乱れないか必ず確認してください。CSSによるフォントファミリー指定の知識がない場合は、フォントを変更しないほうが良いでしょう。

キーボード・ショートカット

オープン操作

PDC

ページ(章)移動の左オフキャンバスオープン

HA

ヘッダー移動モーダルオープン

MS

移動/設定の右オフキャンバスオープン

ヘッダー移動

T

最初のヘッダーへ移動

E

最後のヘッダーへ移動

NJ

次ヘッダー(H2〜H4)へ移動

BK

前ヘッダー(H2〜H4)へ移動

その他

?

このヘルプページ表示
閉じる