在 Laravel 项目开发 RESTful 接口时,很多场景下控制器方法不需要返回具体数据,比如删除资源、更新状态等操作,按照规范应该返回 204 No Content 状态码。但 Laravel 默认对空响应的状态码处理并不统一,手动在每个控制器中设置响应状态会增加重复代码,通过自定义中间件可以统一处理这类场景。

实现思路
核心逻辑是在中间件中获取控制器返回的响应对象,判断响应内容是否为空,如果为空就将响应状态码修改为 204。需要注意区分不同类型的空响应,比如空数组、空字符串、null 等情况,避免误判正常的空数据返回。
创建中间件
首先使用 Artisan 命令创建中间件:
<?php
namespace AppHttpMiddleware;
use Closure;
use IlluminateHttpResponse;
class Auto204ForEmptyResponse
{
/**
* 处理传入的请求
*
* @param IlluminateHttpRequest $request
* @param Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
// 先执行控制器逻辑获取响应
$response = $next($request);
// 只处理成功响应,排除错误响应
if ($response->getStatusCode() >= 200 && $response->getStatusCode() < 300) {
$content = $response->getContent();
// 判断响应内容是否为空:去除空白字符后为空,或者内容是空数组的 JSON 表示
if (empty($content) || $content === '[]' || $content === 'null') {
// 设置 204 状态码,同时清空响应内容
$response->setStatusCode(204);
$response->setContent('');
}
}
return $response;
}
}
注册中间件
创建完成后需要将中间件注册到 Laravel 的中间件列表中,有两种注册方式:
全局注册
如果希望所有接口都生效,可以在 app/Http/Kernel.php 的 $middleware 数组中添加:
protected $middleware = [
// 其他已有中间件
AppHttpMiddlewareAuto204ForEmptyResponse::class,
];
路由分组注册
如果只希望特定路由组生效,可以在 $middlewareGroups 的 api 分组中添加,适合只针对接口路由生效的场景:
protected $middlewareGroups = [
'api' => [
// 其他已有中间件
AppHttpMiddlewareAuto204ForEmptyResponse::class,
],
];
测试验证
编写测试控制器方法验证效果:
<?php
namespace AppHttpControllers;
use IlluminateHttpRequest;
class TestController extends Controller
{
// 空响应场景,应该返回 204
public function emptyResponse()
{
// 不返回任何内容
}
// 返回空数组,应该返回 204
public function emptyArray()
{
return response()->json([]);
}
// 返回正常数据,应该保持 200
public function normalResponse()
{
return response()->json(['id' => 1, 'name' => 'test']);
}
}
配置对应路由后,访问这三个接口,前两个会返回 204 状态码,第三个返回 200 状态码,符合预期效果。
注意事项
- 如果接口需要返回空字符串但状态码不是 204,需要在控制器中手动设置状态码,避免被中间件覆盖
- 中间件执行顺序需要注意,如果有其他修改响应的中间件,要确保该中间件的执行顺序在响应修改逻辑之后
- 对于文件下载、重定向等特殊响应类型,中间件中的判断逻辑不会生效,因为这类响应的内容不为空,不会被误判