メインコンテンツまでスキップ
バージョン: master

HTTP 応答 (HTTP Responses)

応答の作成 (Creating Responses)

文字列と配列

すべてのルートとコントローラは、ユーザーのブラウザーに送り返される応答を返す必要があります。 Laravel は、応答を返すためのいくつかの異なる方法を提供します。最も基本的な応答は、ルートまたはコントローラから文字列を返すことです。フレームワークは、文字列を完全な HTTP 応答に自動的に変換します。

Route::get('/', function () {
return 'Hello World';
});

ルートやコントローラから文字列を返すだけでなく、配列を返すこともできます。フレームワークは配列を JSON 応答に自動的に変換します。

Route::get('/', function () {
return [1, 2, 3];
});

ルートまたはコントローラから Eloquent コレクション を返すこともできることをご存知ですか?これらは自動的に JSON に変換されます。試してみてください!

応答オブジェクト

通常、ルート アクションから単純な文字列や配列を返すだけではありません。代わりに、完全な Illuminate\Http\Response インスタンスまたは views を返します。

完全な Response インスタンスを返すと、応答の HTTP ステータス コードとヘッダーをカスタマイズできます。 Response インスタンスは、HTTP 応答を構築するためのさまざまなメソッドを提供する Symfony\Component\HttpFoundation\Response クラスを継承します。

Route::get('/home', function () {
return response('Hello World', 200)
->header('Content-Type', 'text/plain');
});

Eloquent モデルとコレクション

Eloquent ORM モデルとコレクションをルートとコントローラから直接返すこともできます。これを行うと、Laravel はモデルの 隠し属性 を尊重しながら、モデルとコレクションを JSON 応答に自動的に変換します。

use App\Models\User;

Route::get('/user/{user}', function (User $user) {
return $user;
});

応答にヘッダーを添付する

ほとんどの応答メソッドはチェーン可能であり、応答インスタンスをスムーズに構築できることに留意してください。たとえば、header メソッドを使用して、応答をユーザーに送り返す前に一連のヘッダーを応答に追加できます。

return response($content)
->header('Content-Type', $type)
->header('X-Header-One', 'Header Value')
->header('X-Header-Two', 'Header Value');

または、withHeaders メソッドを使用して、応答に追加するヘッダーの配列を指定することもできます。

return response($content)
->withHeaders([
'Content-Type' => $type,
'X-Header-One' => 'Header Value',
'X-Header-Two' => 'Header Value',
]);

withoutHeader メソッドを使用して、送信応答から特定のヘッダーを削除できます。

return response($content)->withoutHeader('X-Debug');

return response($content)->withoutHeader(['X-Debug', 'X-Powered-By']);

キャッシュ制御ミドルウェア

Laravel には cache.headers ミドルウェアが含まれており、ルートのグループに Cache-Control ヘッダーをすばやく設定するために使用できます。ディレクティブは、対応するキャッシュ制御ディレクティブと同等の「スネーク ケース」を使用して指定する必要があり、セミコロンで区切る必要があります。ディレクティブのリストで etag が指定されている場合、応答コンテンツの MD5 ハッシュが ETag 識別子として自動的に設定されます。

Route::middleware('cache.headers:public;max_age=30;s_maxage=300;stale_while_revalidate=600;etag')->group(function () {
Route::get('/privacy', function () {
// ...
});

Route::get('/terms', function () {
// ...
});
});

応答に Cookie を添付する

cookie メソッドを使用して、発信 Illuminate\Http\Response インスタンスに Cookie を添付できます。名前、値、Cookie が有効であるとみなされる分数をこのメソッドに渡す必要があります。

return response('Hello World')->cookie(
'name', 'value', $minutes
);

cookie メソッドは、使用頻度は低いですが、さらにいくつかの引数も受け入れます。一般に、これらの引数は、PHP のネイティブ setcookie メソッドに与えられる引数と同じ目的と意味を持ちます。

return response('Hello World')->cookie(
'name', 'value', $minutes, $path, $domain, $secure, $httpOnly
);

発信応答とともに Cookie が送信されるようにしたいが、その応答のインスタンスがまだない場合は、Cookie ファサードを使用して、送信時に応答に添付する Cookie を「キュー」に入れることができます。 queue メソッドは、Cookie インスタンスの作成に必要な引数を受け取ります。これらの Cookie は、送信応答がブラウザーに送信される前に添付されます。

use Illuminate\Support\Facades\Cookie;

Cookie::queue('name', 'value', $minutes);

後で応答インスタンスにアタッチできる Symfony\Component\HttpFoundation\Cookie インスタンスを生成したい場合は、グローバル cookie ヘルパを使用できます。この Cookie は、応答インスタンスに添付されない限り、クライアントに送り返されません。

$cookie = cookie('name', 'value', $minutes);

return response('Hello World')->cookie($cookie);

Cookie の期限切れを早める

発信応答の withoutCookie メソッドを使用して Cookie を期限切れにすることで、Cookie を削除できます。

return response('Hello World')->withoutCookie('name');

発信応答のインスタンスをまだ持っていない場合は、Cookie ファサードの expire メソッドを使用して Cookie を期限切れにすることができます。

Cookie::expire('name');

Cookie と暗号化

デフォルトでは、Illuminate\Cookie\Middleware\EncryptCookies ミドルウェアのおかげで、Laravel によって生成されたすべての Cookie は暗号化および署名され、クライアントによる変更や読み取りができなくなります。アプリケーションによって生成された Cookie のサブセットの暗号化を無効にしたい場合は、アプリケーションの bootstrap/app.php ファイルで encryptCookies メソッドを使用できます。

->withMiddleware(function (Middleware $middleware): void {
$middleware->encryptCookies(except: [
'cookie_name',
]);
})

一般に、Cookie の暗号化を無効にしないでください。無効にすると、Cookie がクライアント側のデータ漏洩や改ざんにさらされる可能性があります。

リダイレクト (Redirects)

リダイレクト応答は Illuminate\Http\RedirectResponse クラスのインスタンスであり、ユーザーを別の URL にリダイレクトするために必要な適切なヘッダーが含まれています。 RedirectResponse インスタンスを生成するには、いくつかの方法があります。最も簡単な方法は、グローバル redirect ヘルパを使用することです。

Route::get('/dashboard', function () {
return redirect('/home/dashboard');
});

送信されたフォームが無効な場合など、ユーザーを以前の場所にリダイレクトしたい場合があります。これを行うには、グローバル back ヘルパ関数を使用します。この機能は session を利用するため、back 関数を呼び出すルートが web ミドルウェア グループを使用していることを確認してください。

Route::post('/user/profile', function () {
// Validate the request...

return back()->withInput();
});

名前付きルートへのリダイレクト

パラメーターを指定せずに redirect ヘルパを呼び出すと、Illuminate\Routing\Redirector のインスタンスが返され、Redirector インスタンスの任意のメソッドを呼び出すことができます。たとえば、名前付きルートに RedirectResponse を生成するには、route メソッドを使用できます。

return redirect()->route('login');

ルートにパラメーターがある場合は、それらを route メソッドの 2 番目の引数として渡すことができます。

// For a route with the following URI: /profile/{id}

return redirect()->route('profile', ['id' => 1]);

Eloquent モデルを介したパラメーターの入力

Eloquent モデルから設定されている「ID」パラメータを持つルートにリダイレクトしている場合は、モデル自体を渡すことができます。 ID は自動的に抽出されます。

// For a route with the following URI: /profile/{id}

return redirect()->route('profile', [$user]);

ルート パラメーターに配置される値をカスタマイズしたい場合は、ルート パラメーター定義 (/profile/{id:slug}) で列を指定するか、Eloquent モデルの getRouteKey メソッドをオーバーライドできます。

/**
* Get the value of the model's route key.
*/
public function getRouteKey(): mixed
{
return $this->slug;
}

コントローラアクションへのリダイレクト

コントローラのアクション へのリダイレクトを生成することもできます。これを行うには、コントローラとアクション名を action メソッドに渡します。

use App\Http\Controllers\UserController;

return redirect()->action([UserController::class, 'index']);

コントローラ ルートにパラメーターが必要な場合は、それらを action メソッドの 2 番目の引数として渡すことができます。

return redirect()->action(
[UserController::class, 'profile'], ['id' => 1]
);

外部ドメインへのリダイレクト

場合によっては、アプリケーションの外部のドメインにリダイレクトする必要があるかもしれません。これを行うには、away メソッドを呼び出して、追加の URL エンコード、検証、または検証を行わずに RedirectResponse を作成します。

return redirect()->away('https://www.google.com');

フラッシュされたセッション データによるリダイレクト

通常、新しい URL へのリダイレクトと セッションにデータをフラッシュする は同時に行われます。通常、これはアクションが正常に実行された後で、成功メッセージをセッションにフラッシュするときに行われます。便宜上、RedirectResponse インスタンスを作成し、単一の滑らかなメソッド チェーンでセッションにデータをフラッシュすることができます。

Route::post('/user/profile', function () {
// ...

return redirect('/dashboard')->with('status', 'Profile updated!');
});

ユーザーがリダイレクトされた後、session からフラッシュされたメッセージを表示できます。たとえば、Blade 構文 を使用すると、次のようになります。

@if (session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
@endif

入力によるリダイレクト

RedirectResponse インスタンスによって提供される withInput メソッドを使用して、ユーザーを新しい場所にリダイレクトする前に、現在のリクエストの入力データをセッションにフラッシュできます。これは通常、ユーザーが検証エラーに遭遇した場合に行われます。入力がセッションにフラッシュされると、次のリクエスト中に それを取得します を実行してフォームに再入力することが簡単にできます。

return back()->withInput();

他の応答タイプ (Other Response Types)

response ヘルパは、他のタイプの応答インスタンスを生成するために使用できます。 response ヘルパが引数なしで呼び出されると、Illuminate\Contracts\Routing\ResponseFactory contract の実装が返されます。この規約は、応答を生成するためのいくつかの便利な方法を提供します。

回答を見る

応答のステータスとヘッダーを制御する必要があるが、応答のコンテンツとして view を返す必要がある場合は、view メソッドを使用する必要があります。

return response()
->view('hello', $data, 200)
->header('Content-Type', $type);

もちろん、カスタム HTTP ステータス コードやカスタム ヘッダーを渡す必要がない場合は、グローバル view ヘルパ関数を使用できます。

JSON 応答

json メソッドは、Content-Type ヘッダーを application/json に自動的に設定し、json_encode PHP 関数を使用して指定された配列を JSON に変換します。

return response()->json([
'name' => 'Abigail',
'state' => 'CA',
]);

JSONP 応答を作成したい場合は、json メソッドを withCallback メソッドと組み合わせて使用​​できます。

return response()
->json(['name' => 'Abigail', 'state' => 'CA'])
->withCallback($request->input('callback'));

ファイルのダウンロード

download メソッドは、ユーザーのブラウザに指定されたパスにファイルをダウンロードさせる応答を生成するために使用できます。 download メソッドは、メソッドの 2 番目の引数としてファイル名を受け入れます。これにより、ファイルをダウンロードするユーザーに表示されるファイル名が決まります。最後に、HTTP ヘッダーの配列を 3 番目の引数としてメソッドに渡すことができます。

return response()->download($pathToFile);

return response()->download($pathToFile, $name, $headers);

ファイルのダウンロードを管理する Symfony HttpFoundation では、ダウンロードされるファイルに ASCII ファイル名が付いている必要があります。

ファイル応答

file メソッドは、ダウンロードを開始する代わりに、画像や PDF などのファイルをユーザーのブラウザーに直接表示するために使用できます。このメソッドは、ファイルへの絶対パスを最初の引数として受け入れ、ヘッダーの配列を 2 番目の引数として受け入れます。

return response()->file($pathToFile);

return response()->file($pathToFile, $headers);

ストリーミングされた応答 (Streamed Responses)

データの生成時にクライアントにデータをストリーミングすることで、特に非常に大規模な応答の場合、メモリ使用量を大幅に削減し、パフォーマンスを向上させることができます。ストリーミング応答を使用すると、サーバーがデータの送信を完了する前に、クライアントがデータの処理を開始できます。

Route::get('/stream', function () {
return response()->stream(function (): void {
foreach (['developer', 'admin'] as $string) {
echo $string;
ob_flush();
flush();
sleep(2); // Simulate delay between chunks...
}
}, 200, ['X-Accel-Buffering' => 'no']);
});

便宜上、stream メソッドに指定したクロージャが Generator を返す場合、Laravel はジェネレーターによって返された文字列間の出力バッファを自動的にフラッシュし、Nginx の出力バッファリングを無効にします。

Route::post('/chat', function () {
return response()->stream(function (): Generator {
$stream = OpenAI::client()->chat()->createStreamed(...);

foreach ($stream as $response) {
yield $response->choices[0];
}
});
});

ストリーミングされた応答の消費

ストリーミングされた応答は、Laravel の stream npm パッケージを使用して消費できます。これは、Laravel 応答およびイベント ストリームと対話するための便利な API を提供します。まず、@laravel/stream-react または @laravel/stream-vue パッケージをインストールします。

npm install @laravel/stream-react
npm install @laravel/stream-vue

次に、useStream を使用してイベント ストリームを消費できます。ストリーム URL を指定すると、Laravel アプリケーションからコンテンツが返されると、フックは連結された応答で data を自動的に更新します。

import { useStream } from "@laravel/stream-react";

function App() {
const { data, isFetching, isStreaming, send } = useStream("chat");

const sendMessage = () => {
send({
message: `Current timestamp: ${Date.now()}`,
});
};

return (
<div>
<div>{data}</div>
{isFetching && <div>Connecting...</div>}
{isStreaming && <div>Generating...</div>}
<button onClick={sendMessage}>Send Message</button>
</div>
);
}
<script setup lang="ts">
import { useStream } from "@laravel/stream-vue";

const { data, isFetching, isStreaming, send } = useStream("chat");

const sendMessage = () => {
send({
message: `Current timestamp: ${Date.now()}`,
});
};
</script>

<template>
<div>
<div>{{ data }}</div>
<div v-if="isFetching">Connecting...</div>
<div v-if="isStreaming">Generating...</div>
<button @click="sendMessage">Send Message</button>
</div>
</template>

send 経由でデータをストリームに送り返すと、新しいデータを送信する前にストリームへのアクティブな接続がキャンセルされます。すべてのリクエストは JSON POST リクエストとして送信されます。

useStream フックはアプリケーションに対して POST リクエストを行うため、有効な CSRF トークンが必要です。 CSRF トークンを提供する最も簡単な方法は、アプリケーションレイアウトのヘッドにメタタグを介して含めます です。

useStream に指定される 2 番目の引数は、ストリーム消費動作をカスタマイズするために使用できるオプション オブジェクトです。このオブジェクトのデフォルト値を以下に示します。

import { useStream } from "@laravel/stream-react";

function App() {
const { data } = useStream("chat", {
id: undefined,
initialInput: undefined,
headers: undefined,
csrfToken: undefined,
onResponse: (response: Response) => void,
onData: (data: string) => void,
onCancel: () => void,
onFinish: () => void,
onError: (error: Error) => void,
});

return <div>{data}</div>;
}
<script setup lang="ts">
import { useStream } from "@laravel/stream-vue";

const { data } = useStream("chat", {
id: undefined,
initialInput: undefined,
headers: undefined,
csrfToken: undefined,
onResponse: (response: Response) => void,
onData: (data: string) => void,
onCancel: () => void,
onFinish: () => void,
onError: (error: Error) => void,
});
</script>

<template>
<div>{{ data }}</div>
</template>

onResponse は、ストリームからの初期応答が成功した後にトリガーされ、生の Response がコールバックに渡されます。各チャンクが受信されると、onData が呼び出され、現在のチャンクがコールバックに渡されます。 onFinish は、ストリームが終了したとき、およびフェッチ/読み取りサイクル中にエラーがスローされたときに呼び出されます。

デフォルトでは、初期化時にストリームに対してリクエストは行われません。 initialInput オプションを使用して、初期ペイロードをストリームに渡すことができます。

import { useStream } from "@laravel/stream-react";

function App() {
const { data } = useStream("chat", {
initialInput: {
message: "Introduce yourself.",
},
});

return <div>{data}</div>;
}
<script setup lang="ts">
import { useStream } from "@laravel/stream-vue";

const { data } = useStream("chat", {
initialInput: {
message: "Introduce yourself.",
},
});
</script>

<template>
<div>{{ data }}</div>
</template>

ストリームを手動でキャンセルするには、フックから返された cancel メソッドを使用できます。

import { useStream } from "@laravel/stream-react";

function App() {
const { data, cancel } = useStream("chat");

return (
<div>
<div>{data}</div>
<button onClick={cancel}>Cancel</button>
</div>
);
}
<script setup lang="ts">
import { useStream } from "@laravel/stream-vue";

const { data, cancel } = useStream("chat");
</script>

<template>
<div>
<div>{{ data }}</div>
<button @click="cancel">Cancel</button>
</div>
</template>

useStream フックが使用されるたびに、ストリームを識別するためにランダムな id が生成されます。これは、X-STREAM-ID ヘッダー内の各リクエストとともにサーバーに返送されます。複数のコンポーネントから同じストリームを使用する場合、独自の id を提供することで、ストリームの読み取りと書き込みを行うことができます。

// App.tsx
import { useStream } from "@laravel/stream-react";

function App() {
const { data, id } = useStream("chat");

return (
<div>
<div>{data}</div>
<StreamStatus id={id} />
</div>
);
}

// StreamStatus.tsx
import { useStream } from "@laravel/stream-react";

function StreamStatus({ id }) {
const { isFetching, isStreaming } = useStream("chat", { id });

return (
<div>
{isFetching && <div>Connecting...</div>}
{isStreaming && <div>Generating...</div>}
</div>
);
}
<!-- App.vue -->
<script setup lang="ts">
import { useStream } from "@laravel/stream-vue";
import StreamStatus from "./StreamStatus.vue";

const { data, id } = useStream("chat");
</script>

<template>
<div>
<div>{{ data }}</div>
<StreamStatus :id="id" />
</div>
</template>

<!-- StreamStatus.vue -->
<script setup lang="ts">
import { useStream } from "@laravel/stream-vue";

const props = defineProps<{
id: string;
}>();

const { isFetching, isStreaming } = useStream("chat", { id: props.id });
</script>

<template>
<div>
<div v-if="isFetching">Connecting...</div>
<div v-if="isStreaming">Generating...</div>
</div>
</template>

ストリーミングされた JSON 応答

JSON データを段階的にストリーミングする必要がある場合は、streamJson メソッドを利用できます。この方法は、JavaScript で簡単に解析できる形式でブラウザに段階的に送信する必要がある大規模なデータセットに特に役立ちます。

use App\Models\User;

Route::get('/users.json', function () {
return response()->streamJson([
'users' => User::cursor(),
]);
});

useJsonStream フックは、ストリーミング終了後にデータを JSON として解析しようとする点を除いて、useStreamフック と同じです。

import { useJsonStream } from "@laravel/stream-react";

type User = {
id: number;
name: string;
email: string;
};

function App() {
const { data, send } = useJsonStream<{ users: User[] }>("users");

const loadUsers = () => {
send({
query: "taylor",
});
};

return (
<div>
<ul>
{data?.users.map((user) => (
<li>
{user.id}: {user.name}
</li>
))}
</ul>
<button onClick={loadUsers}>Load Users</button>
</div>
);
}
<script setup lang="ts">
import { useJsonStream } from "@laravel/stream-vue";

type User = {
id: number;
name: string;
email: string;
};

const { data, send } = useJsonStream<{ users: User[] }>("users");

const loadUsers = () => {
send({
query: "taylor",
});
};
</script>

<template>
<div>
<ul>
<li v-for="user in data?.users" :key="user.id">
{{ user.id }}: {{ user.name }}
</li>
</ul>
<button @click="loadUsers">Load Users</button>
</div>
</template>

イベントストリーム (SSE)

eventStream メソッドは、text/event-stream コンテンツ タイプを使用してサーバー送信イベント (SSE) ストリーミング応答を返すために使用できます。 eventStream メソッドは、応答が利用可能になったときに yield がストリームに応答する必要があるクロージャを受け入れます。

Route::get('/chat', function () {
return response()->eventStream(function () {
$stream = OpenAI::client()->chat()->createStreamed(...);

foreach ($stream as $response) {
yield $response->choices[0];
}
});
});

イベントの名前をカスタマイズしたい場合は、StreamedEvent クラスのインスタンスを生成します。

use Illuminate\Http\StreamedEvent;

yield new StreamedEvent(
event: 'update',
data: $response->choices[0],
);

イベントストリームの消費

イベントストリームは、Laravelのstream npmパッケージを使用して消費できます。これは、Laravelイベントストリームと対話するための便利なAPIを提供します。まず、@laravel/stream-react または @laravel/stream-vue パッケージをインストールします。

npm install @laravel/stream-react
npm install @laravel/stream-vue

次に、useEventStream を使用してイベント ストリームを消費できます。ストリーム URL を指定すると、Laravel アプリケーションからメッセージが返されると、フックは連結された応答で message を自動的に更新します。

import { useEventStream } from "@laravel/stream-react";

function App() {
const { message } = useEventStream("/chat");

return <div>{message}</div>;
}
<script setup lang="ts">
import { useEventStream } from "@laravel/stream-vue";

const { message } = useEventStream("/chat");
</script>

<template>
<div>{{ message }}</div>
</template>

useEventStream に指定される 2 番目の引数は、ストリーム消費動作をカスタマイズするために使用できるオプション オブジェクトです。このオブジェクトのデフォルト値を以下に示します。

import { useEventStream } from "@laravel/stream-react";

function App() {
const { message } = useEventStream("/stream", {
eventName: "update",
onMessage: (message) => {
//
},
onError: (error) => {
//
},
onComplete: () => {
//
},
endSignal: "</stream>",
glue: " ",
});

return <div>{message}</div>;
}
<script setup lang="ts">
import { useEventStream } from "@laravel/stream-vue";

const { message } = useEventStream("/chat", {
eventName: "update",
onMessage: (message) => {
// ...
},
onError: (error) => {
// ...
},
onComplete: () => {
// ...
},
endSignal: "</stream>",
glue: " ",
});
</script>

イベント ストリームは、アプリケーションのフロントエンドによって EventSource オブジェクトを介して手動で使用することもできます。 eventStream メソッドは、ストリームが完了すると、イベント ストリームに </stream> 更新を自動的に送信します。

const source = new EventSource('/chat');

source.addEventListener('update', (event) => {
if (event.data === '</stream>') {
source.close();

return;
}

console.log(event.data);
});

イベント ストリームに送信される最終イベントをカスタマイズするには、StreamedEvent インスタンスを eventStream メソッドの endStreamWith 引数に指定します。

return response()->eventStream(function () {
// ...
}, endStreamWith: new StreamedEvent(event: 'update', data: '</stream>'));

ストリーミングダウンロード

場合によっては、操作の内容をディスクに書き込むことなく、特定の操作の文字列応答をダウンロード可能な応答に変換したい場合があります。このシナリオでは、streamDownload メソッドを使用できます。このメソッドは、コールバック、ファイル名、およびオプションのヘッダー配列を引数として受け取ります。

use App\Services\GitHub;

return response()->streamDownload(function () {
echo GitHub::api('repo')
->contents()
->readme('laravel', 'laravel')['contents'];
}, 'laravel-readme.md');

応答マクロ (Response Macros)

さまざまなルートやコントローラで再利用できるカスタム応答を定義したい場合は、Response ファサードで macro メソッドを使用できます。通常、このメソッドは、アプリケーションの サービスプロバイダ の 1 つ (App\Providers\AppServiceProvider サービスプロバイダなど) の boot メソッドから呼び出す必要があります。

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Response;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Response::macro('caps', function (string $value) {
return Response::make(strtoupper($value));
});
}
}

macro 関数は、最初の引数として名前を受け入れ、2 番目の引数としてクロージャーを受け入れます。マクロのクロージャーは、ResponseFactory 実装または response ヘルパからマクロ名を呼び出すときに実行されます。

return response()->caps('foo');