HTTP 响应
创建响应
字符串与数组
所有的路由和控制器都应该返回一个响应发送回用户的浏览器。Laravel 提供了多种不同的方式来返回响应。最基本的响应是从路由或控制器返回一个字符串。框架会自动将该字符串转换为完整的 HTTP 响应。
1Route::get('/', function () {2 return 'Hello World';3});
除了从路由和控制器返回字符串外,你也可以返回数组。框架会自动将数组转换为 JSON 响应。
1Route::get('/', function () {2 return [1, 2, 3];3});
你知道吗?你还可以从路由或控制器中返回 Eloquent 集合。它们会被自动转换为 JSON。试一试吧!
响应对象
通常,你不仅仅会从路由动作中返回简单的字符串或数组,而是返回完整的 Illuminate\Http\Response 实例或 视图。
返回一个完整的 Response 实例允许你自定义响应的 HTTP 状态码和响应头。Response 实例继承自 Symfony\Component\HttpFoundation\Response 类,该类提供了多种用于构建 HTTP 响应的方法。
1Route::get('/home', function () {2 return response('Hello World', 200)3 ->header('Content-Type', 'text/plain');4});
Eloquent 模型与集合
你也可以直接从路由和控制器返回 Eloquent ORM 模型和集合。当你这样做时,Laravel 会在遵守模型 隐藏属性 的前提下,自动将模型和集合转换为 JSON 响应。
1use App\Models\User;2 3Route::get('/user/{user}', function (User $user) {4 return $user;5});
向响应添加响应头
请记住,大多数响应方法都是可以链式调用的,这允许你流畅地构建响应实例。例如,你可以在将响应发送回用户之前,使用 header 方法添加一系列响应头。
1return response($content)2 ->header('Content-Type', $type)3 ->header('X-Header-One', 'Header Value')4 ->header('X-Header-Two', 'Header Value');
或者,你可以使用 withHeaders 方法指定一个数组,将其作为响应头添加到响应中。
1return response($content)2 ->withHeaders([3 'Content-Type' => $type,4 'X-Header-One' => 'Header Value',5 'X-Header-Two' => 'Header Value',6 ]);
你可以使用 withoutHeader 方法从外发响应中移除指定的响应头。
1return response($content)->withoutHeader('X-Debug');2 3return response($content)->withoutHeader(['X-Debug', 'X-Powered-By']);
缓存控制中间件
Laravel 包含一个 cache.headers 中间件,可用于快速为一组路由设置 Cache-Control 响应头。指令应使用对应 Cache-Control 指令的“蛇形命名法(snake case)”等效项,并以分号分隔。如果指令列表中指定了 etag,则响应内容的 MD5 哈希值将自动设置为 ETag 标识符。
1Route::middleware('cache.headers:public;max_age=30;s_maxage=300;stale_while_revalidate=600;etag')->group(function () {2 Route::get('/privacy', function () {3 // ...4 });5 6 Route::get('/terms', function () {7 // ...8 });9});
向响应添加 Cookie
你可以使用 cookie 方法将 Cookie 添加到外发的 Illuminate\Http\Response 实例中。你应该向此方法传递名称、值以及 Cookie 有效的分钟数。
1return response('Hello World')->cookie(2 'name', 'value', $minutes3);
cookie 方法还接受一些不太常用的附加参数。通常,这些参数的作用和意义与 PHP 原生 setcookie 方法的参数相同。
1return response('Hello World')->cookie(2 'name', 'value', $minutes, $path, $domain, $secure, $httpOnly3);
如果你希望确保 Cookie 随外发响应发送,但你还没有该响应的实例,你可以使用 Cookie 门面(facade)来“排队”等待发送响应时附加这些 Cookie。queue 方法接受创建 Cookie 实例所需的参数。这些 Cookie 将在发送到浏览器之前被附加到外发响应中。
1use Illuminate\Support\Facades\Cookie;2 3Cookie::queue('name', 'value', $minutes);
生成 Cookie 实例
如果你想生成一个 Symfony\Component\HttpFoundation\Cookie 实例,以便稍后附加到响应实例中,你可以使用全局的 cookie 辅助函数。除非将其附加到响应实例,否则此 Cookie 不会被发送回客户端。
1$cookie = cookie('name', 'value', $minutes);2 3return response('Hello World')->cookie($cookie);
提前让 Cookie 过期
你可以通过外发响应的 withoutCookie 方法移除一个 Cookie,使其过期。
1return response('Hello World')->withoutCookie('name');
如果你还没有外发响应的实例,你可以使用 Cookie 门面的 expire 方法让 Cookie 过期。
1Cookie::expire('name');
Cookie 与加密
默认情况下,由于 Illuminate\Cookie\Middleware\EncryptCookies 中间件的存在,Laravel 生成的所有 Cookie 都会经过加密和签名,因此客户端无法对其进行修改或读取。如果你想为应用程序生成的某些 Cookie 禁用加密,可以在应用程序的 bootstrap/app.php 文件中使用 encryptCookies 方法。
1->withMiddleware(function (Middleware $middleware): void {2 $middleware->encryptCookies(except: [3 'cookie_name',4 ]);5})
通常情况下,永远不应禁用 Cookie 加密,因为这会将你的 Cookie 暴露在潜在的客户端数据泄露和篡改风险中。
重定向
重定向响应是 Illuminate\Http\RedirectResponse 类的实例,包含将用户重定向到另一个 URL 所需的正确响应头。生成 RedirectResponse 实例有多种方法,最简单的方法是使用全局 redirect 辅助函数。
1Route::get('/dashboard', function () {2 return redirect('/home/dashboard');3});
有时你可能希望将用户重定向回上一个位置,例如在提交的表单无效时。你可以使用全局的 back 辅助函数来实现。由于此功能利用了 session,请确保调用 back 函数的路由使用了 web 中间件组。
1Route::post('/user/profile', function () {2 // Validate the request...3 4 return back()->withInput();5});
重定向到命名路由
当你调用不带参数的 redirect 辅助函数时,会返回一个 Illuminate\Routing\Redirector 实例,允许你在 Redirector 实例上调用任何方法。例如,要生成指向命名路由的 RedirectResponse,可以使用 route 方法。
1return redirect()->route('login');
如果你的路由包含参数,可以将它们作为第二个参数传递给 route 方法。
1// For a route with the following URI: /profile/{id}2 3return redirect()->route('profile', ['id' => 1]);
通过 Eloquent 模型填充参数
如果你要重定向到的路由包含一个从 Eloquent 模型填充的“ID”参数,你可以直接传递该模型实例。ID 将会自动提取。
1// For a route with the following URI: /profile/{id}2 3return redirect()->route('profile', [$user]);
如果你想自定义路由参数中使用的值,可以在路由参数定义中指定列名(例如 /profile/{id:slug}),或者在 Eloquent 模型中重写 getRouteKey 方法。
1/**2 * Get the value of the model's route key.3 */4public function getRouteKey(): mixed5{6 return $this->slug;7}
重定向到控制器动作
你还可以生成指向 控制器动作 的重定向。为此,请将控制器名称和动作名称传递给 action 方法。
1use App\Http\Controllers\UserController;2 3return redirect()->action([UserController::class, 'index']);
如果你的控制器路由需要参数,可以将它们作为第二个参数传递给 action 方法。
1return redirect()->action(2 [UserController::class, 'profile'], ['id' => 1]3);
重定向到外部域名
有时你可能需要重定向到应用程序之外的域名。你可以通过调用 away 方法来实现,它会创建一个不进行任何额外 URL 编码、验证或检查的 RedirectResponse。
1return redirect()->away('https://www.google.com');
带闪存会话数据的重定向
重定向到新 URL 和 将数据闪存到 session 通常同时进行。这通常在成功执行某个操作后完成,例如将成功消息闪存到 session。为了方便起见,你可以在一个流畅的方法链中创建一个 RedirectResponse 实例并将数据闪存到 session。
1Route::post('/user/profile', function () {2 // ...3 4 return redirect('/dashboard')->with('status', 'Profile updated!');5});
用户被重定向后,你可以从 session 中显示闪存的消息。例如,使用 Blade 语法。
1@if (session('status'))2 <div class="alert alert-success">3 {{ session('status') }}4 </div>5@endif
重定向并携带输入数据
你可以使用 RedirectResponse 实例提供的 withInput 方法,在重定向用户到新位置之前,将当前请求的输入数据闪存到 session。这通常在用户遇到验证错误时使用。一旦输入数据被闪存到 session,你就可以在下一次请求时轻松地 检索它 以重新填充表单。
1return back()->withInput();
其他响应类型
response 辅助函数可用于生成其他类型的响应实例。当不带参数调用 response 辅助函数时,会返回一个实现了 Illuminate\Contracts\Routing\ResponseFactory 契约 的实例。该契约提供了多种用于生成响应的有用方法。
视图响应
如果你需要控制响应的状态码和响应头,同时又需要将 视图 作为响应内容返回,你应该使用 view 方法。
1return response()2 ->view('hello', $data, 200)3 ->header('Content-Type', $type);
当然,如果你不需要传递自定义的 HTTP 状态码或自定义响应头,可以直接使用全局 view 辅助函数。
JSON 响应
json 方法会自动将 Content-Type 响应头设置为 application/json,并使用 PHP 的 json_encode 函数将给定的数组转换为 JSON。
1return response()->json([2 'name' => 'Abigail',3 'state' => 'CA',4]);
如果你想创建一个 JSONP 响应,可以将 json 方法与 withCallback 方法结合使用。
1return response()2 ->json(['name' => 'Abigail', 'state' => 'CA'])3 ->withCallback($request->input('callback'));
文件下载
download 方法可用于生成强制用户浏览器下载指定路径文件的响应。download 方法接受文件名作为第二个参数,该参数将决定用户下载文件时看到的文件名。最后,你可以将 HTTP 响应头数组作为第三个参数传递给该方法。
1return response()->download($pathToFile);2 3return response()->download($pathToFile, $name, $headers);
管理文件下载的 Symfony HttpFoundation 要求被下载的文件名必须是 ASCII 编码的。
文件响应
file 方法可用于直接在用户浏览器中显示文件(例如图片或 PDF),而不是触发下载。此方法接受文件的绝对路径作为第一个参数,响应头数组作为第二个参数。
1return response()->file($pathToFile);2 3return response()->file($pathToFile, $headers);
流式响应
通过在数据生成时将其流式传输给客户端,你可以显著减少内存占用并提高性能,特别是在处理非常大的响应时。流式响应允许客户端在服务器完成发送之前就开始处理数据。
1Route::get('/stream', function () { 2 return response()->stream(function (): void { 3 foreach (['developer', 'admin'] as $string) { 4 echo $string; 5 ob_flush(); 6 flush(); 7 sleep(2); // Simulate delay between chunks... 8 } 9 }, 200, ['X-Accel-Buffering' => 'no']);10});
为了方便起见,如果你传递给 stream 方法的闭包返回一个 生成器(Generator),Laravel 将自动在生成器返回的字符串之间刷新输出缓冲区,并禁用 Nginx 输出缓冲。
1Route::post('/chat', function () {2 return response()->stream(function (): Generator {3 $stream = OpenAI::client()->chat()->createStreamed(...);4 5 foreach ($stream as $response) {6 yield $response->choices[0];7 }8 });9});
消费流式响应
流式响应可以使用 Laravel 的 stream npm 包来消费,该包为与 Laravel 响应和事件流交互提供了便捷的 API。要开始使用,请安装 @laravel/stream-react、@laravel/stream-vue 或 @laravel/stream-svelte 包。
1npm install @laravel/stream-react
1npm install @laravel/stream-vue
1npm install @laravel/stream-svelte
然后,可以使用 useStream 来消费事件流。在提供流 URL 后,该 Hook 会随着 Laravel 应用程序返回内容,自动更新 data 为拼接后的响应。
1import { useStream } from "@laravel/stream-react"; 2 3function App() { 4 const { data, isFetching, isStreaming, send } = useStream("chat"); 5 6 const sendMessage = () => { 7 send({ 8 message: `Current timestamp: ${Date.now()}`, 9 });10 };11 12 return (13 <div>14 <div>{data}</div>15 {isFetching && <div>Connecting...</div>}16 {isStreaming && <div>Generating...</div>}17 <button onClick={sendMessage}>Send Message</button>18 </div>19 );20}
1<script setup lang="ts"> 2import { useStream } from "@laravel/stream-vue"; 3 4const { data, isFetching, isStreaming, send } = useStream("chat"); 5 6const sendMessage = () => { 7 send({ 8 message: `Current timestamp: ${Date.now()}`, 9 });10};11</script>12 13<template>14 <div>15 <div>{{ data }}</div>16 <div v-if="isFetching">Connecting...</div>17 <div v-if="isStreaming">Generating...</div>18 <button @click="sendMessage">Send Message</button>19 </div>20</template>
<script>import { useStream } from "@laravel/stream-svelte";const stream = useStream("chat");const sendMessage = () => { stream.send({ message: `Current timestamp: ${Date.now()}`, });};</script><div> <div>{$stream.data}</div> {#if $stream.isFetching} <div>Connecting...</div> {/if} {#if $stream.isStreaming} <div>Generating...</div> {/if} <button onclick={sendMessage}>Send Message</button></div>
当通过 send 将数据传回流时,活动连接会在发送新数据之前取消。所有请求都作为 JSON POST 请求发送。
由于 useStream Hook 会向你的应用程序发起 POST 请求,因此需要有效的 CSRF 令牌。提供 CSRF 令牌最简单的方法是 将其包含在应用程序布局的 head 标签中的 meta 标签里。
传递给 useStream 的第二个参数是一个选项对象,你可以用它来自定义流消费行为。该对象的默认值如下所示:
1import { useStream } from "@laravel/stream-react"; 2 3function App() { 4 const { data } = useStream("chat", { 5 id: undefined, 6 initialInput: undefined, 7 headers: undefined, 8 csrfToken: undefined, 9 onResponse: (response: Response) => void,10 onData: (data: string) => void,11 onCancel: () => void,12 onFinish: () => void,13 onError: (error: Error) => void,14 });15 16 return <div>{data}</div>;17}
1<script setup lang="ts"> 2import { useStream } from "@laravel/stream-vue"; 3 4const { data } = useStream("chat", { 5 id: undefined, 6 initialInput: undefined, 7 headers: undefined, 8 csrfToken: undefined, 9 onResponse: (response: Response) => void,10 onData: (data: string) => void,11 onCancel: () => void,12 onFinish: () => void,13 onError: (error: Error) => void,14});15</script>16 17<template>18 <div>{{ data }}</div>19</template>
1<script> 2import { useStream } from "@laravel/stream-svelte"; 3 4const stream = useStream("chat", { 5 id: undefined, 6 initialInput: undefined, 7 headers: undefined, 8 csrfToken: undefined, 9 onResponse: (response) => {},10 onData: (data) => {},11 onCancel: () => {},12 onFinish: () => {},13 onError: (error) => {},14});15</script>16 17<div>{$stream.data}</div>
onResponse 在流成功获得初始响应后触发,原始 Response 会被传递给回调函数。onData 在收到每个数据块时被调用,当前数据块会被传递给回调函数。onFinish 在流结束时以及获取/读取周期中抛出错误时被调用。
默认情况下,初始化时不会向流发出请求。你可以使用 initialInput 选项向流传递初始有效载荷。
1import { useStream } from "@laravel/stream-react"; 2 3function App() { 4 const { data } = useStream("chat", { 5 initialInput: { 6 message: "Introduce yourself.", 7 }, 8 }); 9 10 return <div>{data}</div>;11}
1<script setup lang="ts"> 2import { useStream } from "@laravel/stream-vue"; 3 4const { data } = useStream("chat", { 5 initialInput: { 6 message: "Introduce yourself.", 7 }, 8}); 9</script>10 11<template>12 <div>{{ data }}</div>13</template>
1<script> 2import { useStream } from "@laravel/stream-svelte"; 3 4const stream = useStream("chat", { 5 initialInput: { 6 message: "Introduce yourself.", 7 }, 8}); 9</script>10 11<div>{$stream.data}</div>
要手动取消流,你可以使用 Hook 返回的 cancel 方法。
1import { useStream } from "@laravel/stream-react"; 2 3function App() { 4 const { data, cancel } = useStream("chat"); 5 6 return ( 7 <div> 8 <div>{data}</div> 9 <button onClick={cancel}>Cancel</button>10 </div>11 );12}
1<script setup lang="ts"> 2import { useStream } from "@laravel/stream-vue"; 3 4const { data, cancel } = useStream("chat"); 5</script> 6 7<template> 8 <div> 9 <div>{{ data }}</div>10 <button @click="cancel">Cancel</button>11 </div>12</template>
1<script> 2import { useStream } from "@laravel/stream-svelte"; 3 4const stream = useStream("chat"); 5</script> 6 7<div> 8 <div>{$stream.data}</div> 9 <button onclick={() => stream.cancel()}>Cancel</button>10</div>
每次使用 useStream Hook 时,都会生成一个随机的 id 来标识该流。该 ID 会在每个请求中通过 X-STREAM-ID 响应头发送回服务器。当从多个组件消费同一个流时,你可以通过提供自己的 id 来读取和写入该流。
1// App.tsx 2import { useStream } from "@laravel/stream-react"; 3 4function App() { 5 const { data, id } = useStream("chat"); 6 7 return ( 8 <div> 9 <div>{data}</div>10 <StreamStatus id={id} />11 </div>12 );13}14 15// StreamStatus.tsx16import { useStream } from "@laravel/stream-react";17 18function StreamStatus({ id }) {19 const { isFetching, isStreaming } = useStream("chat", { id });20 21 return (22 <div>23 {isFetching && <div>Connecting...</div>}24 {isStreaming && <div>Generating...</div>}25 </div>26 );27}
1<!-- App.vue --> 2<script setup lang="ts"> 3import { useStream } from "@laravel/stream-vue"; 4import StreamStatus from "./StreamStatus.vue"; 5 6const { data, id } = useStream("chat"); 7</script> 8 9<template>10 <div>11 <div>{{ data }}</div>12 <StreamStatus :id="id" />13 </div>14</template>15 16<!-- StreamStatus.vue -->17<script setup lang="ts">18import { useStream } from "@laravel/stream-vue";19 20const props = defineProps<{21 id: string;22}>();23 24const { isFetching, isStreaming } = useStream("chat", { id: props.id });25</script>26 27<template>28 <div>29 <div v-if="isFetching">Connecting...</div>30 <div v-if="isStreaming">Generating...</div>31 </div>32</template>
<!-- App.svelte --><script>import { useStream } from "@laravel/stream-svelte";import StreamStatus from "./StreamStatus.svelte";const stream = useStream("chat");</script><div> <div>{$stream.data}</div> <StreamStatus id={stream.id} /></div><!-- StreamStatus.svelte --><script>import { useStream } from "@laravel/stream-svelte";let { id } = $props();const stream = useStream("chat", { id });</script><div> {#if $stream.isFetching} <div>Connecting...</div> {/if} {#if $stream.isStreaming} <div>Generating...</div> {/if}</div>
流式 JSON 响应
如果你需要增量地流式传输 JSON 数据,可以使用 streamJson 方法。此方法对于需要逐步发送到浏览器并能被 JavaScript 轻松解析的大型数据集特别有用。
1use App\Models\User;2 3Route::get('/users.json', function () {4 return response()->streamJson([5 'users' => User::cursor(),6 ]);7});
useJsonStream Hook 与 useStream Hook 基本相同,区别在于它会在流传输完成后尝试将数据解析为 JSON。
1import { useJsonStream } from "@laravel/stream-react"; 2 3type User = { 4 id: number; 5 name: string; 6 email: string; 7}; 8 9function App() {10 const { data, send } = useJsonStream<{ users: User[] }>("users");11 12 const loadUsers = () => {13 send({14 query: "taylor",15 });16 };17 18 return (19 <div>20 <ul>21 {data?.users.map((user) => (22 <li>23 {user.id}: {user.name}24 </li>25 ))}26 </ul>27 <button onClick={loadUsers}>Load Users</button>28 </div>29 );30}
1<script setup lang="ts"> 2import { useJsonStream } from "@laravel/stream-vue"; 3 4type User = { 5 id: number; 6 name: string; 7 email: string; 8}; 9 10const { data, send } = useJsonStream<{ users: User[] }>("users");11 12const loadUsers = () => {13 send({14 query: "taylor",15 });16};17</script>18 19<template>20 <div>21 <ul>22 <li v-for="user in data?.users" :key="user.id">23 {{ user.id }}: {{ user.name }}24 </li>25 </ul>26 <button @click="loadUsers">Load Users</button>27 </div>28</template>
<script>import { useJsonStream } from "@laravel/stream-svelte";const stream = useJsonStream("users");const loadUsers = () => { stream.send({ query: "taylor", });};</script><div> <ul> {#if $stream.data?.users} {#each $stream.data.users as user (user.id)} <li>{user.id}: {user.name}</li> {/each} {/if} </ul> <button onclick={loadUsers}>Load Users</button></div>
事件流 (SSE)
eventStream 方法可用于返回使用 text/event-stream 内容类型的服务器推送事件(SSE)流式响应。eventStream 方法接受一个闭包,该闭包应在响应可用时将其 yield 给流。
1Route::get('/chat', function () {2 return response()->eventStream(function () {3 $stream = OpenAI::client()->chat()->createStreamed(...);4 5 foreach ($stream as $response) {6 yield $response->choices[0];7 }8 });9});
如果你想自定义事件名称,可以 yield 一个 StreamedEvent 类的实例。
1use Illuminate\Http\StreamedEvent;2 3yield new StreamedEvent(4 event: 'update',5 data: $response->choices[0],6);
消费事件流
事件流可以使用 Laravel 的 stream npm 包来消费,该包为与 Laravel 事件流交互提供了便捷的 API。要开始使用,请安装 @laravel/stream-react、@laravel/stream-vue 或 @laravel/stream-svelte 包。
1npm install @laravel/stream-react
1npm install @laravel/stream-vue
1npm install @laravel/stream-svelte
然后,可以使用 useEventStream 来消费事件流。在提供流 URL 后,该 Hook 会随着 Laravel 应用程序返回消息,自动更新 message 为拼接后的响应。
1import { useEventStream } from "@laravel/stream-react";2 3function App() {4 const { message } = useEventStream("/chat");5 6 return <div>{message}</div>;7}
1<script setup lang="ts">2import { useEventStream } from "@laravel/stream-vue";3 4const { message } = useEventStream("/chat");5</script>6 7<template>8 <div>{{ message }}</div>9</template>
1<script>2import { useEventStream } from "@laravel/stream-svelte";3 4const eventStream = useEventStream("/chat");5</script>6 7<div>{$eventStream.message}</div>
传递给 useEventStream 的第二个参数是一个选项对象,你可以用它来自定义流消费行为。该对象的默认值如下所示:
1import { useEventStream } from "@laravel/stream-react"; 2 3function App() { 4 const { message } = useEventStream("/stream", { 5 eventName: "update", 6 onMessage: (message) => { 7 // 8 }, 9 onError: (error) => {10 //11 },12 onComplete: () => {13 //14 },15 endSignal: "</stream>",16 glue: " ",17 });18 19 return <div>{message}</div>;20}
1<script setup lang="ts"> 2import { useEventStream } from "@laravel/stream-vue"; 3 4const { message } = useEventStream("/chat", { 5 eventName: "update", 6 onMessage: (message) => { 7 // ... 8 }, 9 onError: (error) => {10 // ...11 },12 onComplete: () => {13 // ...14 },15 endSignal: "</stream>",16 glue: " ",17});18</script>
1<script> 2import { useEventStream } from "@laravel/stream-svelte"; 3 4const eventStream = useEventStream("/chat", { 5 eventName: "update", 6 onMessage: (event) => { 7 // 8 }, 9 onError: (error) => {10 //11 },12 onComplete: () => {13 //14 },15 endSignal: "</stream>",16 glue: " ",17 replace: false,18});19</script>
事件流也可以通过应用程序前端的 EventSource 对象手动消费。当流完成时,eventStream 方法会自动向事件流发送一个 </stream> 更新。
1const source = new EventSource('/chat'); 2 3source.addEventListener('update', (event) => { 4 if (event.data === '</stream>') { 5 source.close(); 6 7 return; 8 } 9 10 console.log(event.data);11});
要自定义发送到事件流的最终事件,你可以向 eventStream 方法的 endStreamWith 参数提供一个 StreamedEvent 实例。
1return response()->eventStream(function () {2 // ...3}, endStreamWith: new StreamedEvent(event: 'update', data: '</stream>'));
流式下载
有时你可能希望将某个操作的字符串响应转换为可下载的响应,而无需将操作内容写入磁盘。在这种情况下,你可以使用 streamDownload 方法。此方法接受回调函数、文件名以及可选的响应头数组作为参数。
1use App\Services\GitHub;2 3return response()->streamDownload(function () {4 echo GitHub::api('repo')5 ->contents()6 ->readme('laravel', 'laravel')['contents'];7}, 'laravel-readme.md');
响应宏
如果你想定义一个可以在多个路由和控制器中复用的自定义响应,可以使用 Response 门面上的 macro 方法。通常,你应该在应用程序某个 服务提供者(例如 App\Providers\AppServiceProvider)的 boot 方法中调用此方法。
1<?php 2 3namespace App\Providers; 4 5use Illuminate\Support\Facades\Response; 6use Illuminate\Support\ServiceProvider; 7 8class AppServiceProvider extends ServiceProvider 9{10 /**11 * Bootstrap any application services.12 */13 public function boot(): void14 {15 Response::macro('caps', function (string $value) {16 return Response::make(strtoupper($value));17 });18 }19}
macro 函数接受一个名称作为第一个参数,闭包作为第二个参数。当从 ResponseFactory 实现或 response 辅助函数调用该宏名称时,宏的闭包将被执行。
1return response()->caps('foo');