织梦网站需要付费吗模版网站建设企业
2026/1/26 7:51:50 网站建设 项目流程
织梦网站需要付费吗,模版网站建设企业,静态网站 apache,中国住建厅网站官网什么是中间件#xff1f;中间件提供了一种便捷的机制来检查和过滤进入应用的 HTTP 请求。你可以把中间件理解为 HTTP 请求在到达应用核心之前必须经过的一道道关卡。比如#xff0c;Laravel 内置了一个用于验证用户身份的中间件。如果用户未登录#xff0c;中间件会把他们重…什么是中间件中间件提供了一种便捷的机制来检查和过滤进入应用的 HTTP 请求。你可以把中间件理解为 HTTP 请求在到达应用核心之前必须经过的一道道关卡。比如Laravel 内置了一个用于验证用户身份的中间件。如果用户未登录中间件会把他们重定向到登录页。如果已登录中间件就放行让请求继续往下走。除了身份验证中间件还有很多其他用途请求日志跟踪所有传入请求以进行调试和分析CSRF 保护确保请求合法且安全数据验证在数据到达控制器之前进行验证速率限制通过限制请求频率来防止滥用CORS 处理管理跨域资源共享策略API Token 验证认证 API 请求基于角色的访问控制根据用户角色限制访问请求/响应修改在处理或发送之前转换数据中间件的工作原理请求生命周期理解中间件在 Laravel 请求生命周期中的位置很重要。当一个 HTTP 请求进来时它会经历这样的流程请求从 public/index.php 进入Laravel 启动应用并加载服务提供者请求经过全局中间件栈路由器匹配对应的路由执行该路由的中间件请求到达控制器或路由处理器响应原路返回再次经过中间件最终返回给客户端这种管道式架构让每个中间件都可以在请求到达应用逻辑之前对其进行检查、修改甚至直接拦截。创建自定义中间件在 Laravel 12 中用 Artisan 命令创建中间件很简单。我们来一步步看如何创建自定义中间件。步骤 1生成 Middleware使用 make:middleware Artisan 命令创建一个新的 Middleware 类php artisan make:middleware EnsureTokenIsValid这个命令会在 app/Http/Middleware 目录下生成一个新文件里面已经写好了基本的中间件结构。步骤 2编写中间件逻辑打开刚生成的 EnsureTokenIsValid.php你会看到一个带 handle 方法的模板?phpnamespace App\Http\Middleware;use Closure;use Illuminate\Http\Request;use Symfony\Component\HttpFoundation\Response;class EnsureTokenIsValid{/*** Handle an incoming request.** param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next*/public function handle(Request $request, Closure $next): Response{if ($request-input(token) ! my-secret-token) {return redirect(/home)-with(error, Invalid token provided);}return $next($request);}}handle 方法有两个参数$request当前的 HTTP 请求$next下一个中间件的闭包如果想让请求通过就调用 $next($request)。如果要拦截请求就直接返回响应或重定向。步骤 3前置和后置中间件中间件可以在处理请求前后都执行操作。前置中间件在请求到达控制器之前执行?phpnamespace App\Http\Middleware;use Closure;use Illuminate\Http\Request;use Symfony\Component\HttpFoundation\Response;class BeforeMiddleware{public function handle(Request $request, Closure $next): Response{// 在请求被处理之前执行操作Log::info(Request received: . $request-path());return $next($request);}}后置中间件在请求处理完成后执行?phpnamespace App\Http\Middleware;use Closure;use Illuminate\Http\Request;use Symfony\Component\HttpFoundation\Response;class AfterMiddleware{public function handle(Request $request, Closure $next): Response{$response $next($request);// 在请求被处理之后执行操作Log::info(Response sent: . $response-getStatusCode());return $response;}}注册中间件Laravel 12 有个重大变化中间件注册不再用 app/Http/Kernel.php而是移到了 bootstrap/app.php。这样做集中了配置也更好理解。Bootstrap/App.php 的新结构Laravel 12 中 bootstrap/app.php 的基本结构长这样?phpuse Illuminate\Foundation\Application;return Application::configure(basePath: dirname(__DIR__))-withRouting(web: __DIR__./../routes/web.php,api: __DIR__./../routes/api.php,commands: __DIR__./../routes/console.php,health: /up,)-withMiddleware(function ($middleware) {// 在这里注册 Middleware})-withExceptions(function ($exceptions) {//})-create();全局中间件全局中间件会在每个 HTTP 请求上运行。注册方式是在 withMiddleware 闭包中用 append 或 prepend-withMiddleware(function ($middleware) {$middleware-append(\App\Http\Middleware\EnsureTokenIsValid::class);})append 会把中间件加到栈的末尾prepend 则加到开头-withMiddleware(function ($middleware) {$middleware-prepend(\App\Http\Middleware\LogRequests::class);$middleware-append(\App\Http\Middleware\CompressResponse::class);})路由中间件路由中间件只作用于指定的路由或路由组。注册时需要给中间件起个别名用 alias 方法-withMiddleware(function ($middleware) {$middleware-alias([admin \App\Http\Middleware\CheckAdmin::class,verified.email \App\Http\Middleware\EnsureEmailIsVerified::class,check.token \App\Http\Middleware\EnsureTokenIsValid::class,]);})中间件组中间件组可以把多个中间件打包在一起方便批量应用-withMiddleware(function ($middleware) {$middleware-appendToGroup(api, [\App\Http\Middleware\EncryptCookies::class,\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,]);})Laravel 12 已经内置了 web 和 api 组。你可以向它们添加自己的中间件也可以创建新的组。应用中间件到路由注册好中间件后有多种方式可以应用到路由上。单个路由用 middleware 方法给单个路由加中间件use Illuminate\Support\Facades\Route;Route::get(/dashboard, function () {// Dashboard 逻辑})-middleware(auth);多个中间件传一个数组就可以同时应用多个Route::get(/admin/settings, function () {// 管理员设置})-middleware([auth, admin, verified.email]);路由组给一组路由加中间件Route::middleware([auth, verified.email])-group(function () {Route::get(/profile, [ProfileController::class, show]);Route::put(/profile, [ProfileController::class, update]);Route::delete(/profile, [ProfileController::class, destroy]);});在控制器中使用也可以直接在控制器构造函数中指定?phpnamespace App\Http\Controllers;class AdminController extends Controller{public function __construct(){$this-middleware(auth);$this-middleware(admin)-only([destroy, create]);$this-middleware(log.request)-except([index]);}}中间件参数中间件可以接收参数这样能让一个中间件更灵活、更好复用。比如做权限控制或功能开关时就特别有用。创建带参数的中间件下面是一个检查用户角色的例子?phpnamespace App\Http\Middleware;use Closure;use Illuminate\Http\Request;use Symfony\Component\HttpFoundation\Response;class CheckRole{public function handle(Request $request, Closure $next, string $role): Response{if (! $request-user() || ! $request-user()-hasRole($role)) {abort(403, Unauthorized action.);}return $next($request);}}使用带参数的中间件用冒号把参数传给中间件Route::get(/admin/dashboard, function () {// 仅限管理员})-middleware(role:admin);Route::get(/moderator/panel, function () {// 仅限版主})-middleware(role:moderator);也可以传多个参数用逗号隔开Route::get(/content/edit, function () {// 编辑内容})-middleware(role:admin,editor);中间件会把它们当作独立的参数接收public function handle(Request $request, Closure $next, string ...$roles): Response{if (! $request-user() || ! $request-user()-hasAnyRole($roles)) {abort(403, Unauthorized action.);}return $next($request);}依赖注入Laravel 的服务容器会解析所有中间件所以你可以在构造函数中直接注入需要的依赖?phpnamespace App\Http\Middleware;use App\Services\TokenService;use Closure;use Illuminate\Http\Request;use Symfony\Component\HttpFoundation\Response;class ValidateApiToken{protected $tokenService;public function __construct(TokenService $tokenService){$this-tokenService $tokenService;}public function handle(Request $request, Closure $next): Response{$token $request-header(X-API-Token);if (! $this-tokenService-isValid($token)) {return response()-json([error Invalid API token], 401);}return $next($request);}}可终止中间件有时候你想在响应发送给用户之后再做一些事情。这时可以实现 terminate 方法?phpnamespace App\Http\Middleware;use Closure;use Illuminate\Http\Request;use Symfony\Component\HttpFoundation\Response;class TerminableMiddleware{public function handle(Request $request, Closure $next): Response{return $next($request);}public function terminate(Request $request, Response $response): void{// 在响应发送后执行任务// 这不会延迟对用户的响应Log::info(Response completed, [status $response-getStatusCode(),path $request-path(),]);}}terminate 方法会在响应发出后才执行所以不会影响用户体验。适合用来记日志、同步数据或做一些清理工作。实际案例看几个在生产环境中常用的中间件实现。API 限流中间件?phpnamespace App\Http\Middleware;use Closure;use Illuminate\Http\Request;use Illuminate\Support\Facades\Cache;use Symfony\Component\HttpFoundation\Response;class RateLimitApi{public function handle(Request $request, Closure $next, int $maxAttempts 60): Response{$key rate-limit: . $request-ip();$attempts Cache::get($key, 0);if ($attempts $maxAttempts) {return response()-json([error Too many requests. Please try again later.], 429);}Cache::put($key, $attempts 1, now()-addMinute());$response $next($request);$response-headers-set(X-RateLimit-Limit, $maxAttempts);$response-headers-set(X-RateLimit-Remaining, $maxAttempts - $attempts - 1);return $response;}}请求日志中间件?phpnamespace App\Http\Middleware;use Closure;use Illuminate\Http\Request;use Illuminate\Support\Facades\Log;use Symfony\Component\HttpFoundation\Response;class LogRequests{public function handle(Request $request, Closure $next): Response{$startTime microtime(true);$response $next($request);$duration microtime(true) - $startTime;Log::info(HTTP Request, [method $request-method(),url $request-fullUrl(),ip $request-ip(),user_id $request-user()?-id,status $response-getStatusCode(),duration round($duration * 1000, 2) . ms,]);return $response;}}强制 HTTPS 中间件?phpnamespace App\Http\Middleware;use Closure;use Illuminate\Http\Request;use Symfony\Component\HttpFoundation\Response;class ForceHttps{public function handle(Request $request, Closure $next): Response{if (! $request-secure() app()-environment(production)) {return redirect()-secure($request-getRequestUri(), 301);}return $next($request);}}输入清理中间件?phpnamespace App\Http\Middleware;use Closure;use Illuminate\Http\Request;use Symfony\Component\HttpFoundation\Response;class SanitizeInput{public function handle(Request $request, Closure $next): Response{$input $request-all();array_walk_recursive($input, function ($value) {if (is_string($value)) {$value strip_tags($value);$value trim($value);}});$request-merge($input);return $next($request);}}语言切换中间件?phpnamespace App\Http\Middleware;use Closure;use Illuminate\Http\Request;use Illuminate\Support\Facades\App;use Symfony\Component\HttpFoundation\Response;class SetLocale{public function handle(Request $request, Closure $next): Response{$locale $request-segment(1);$availableLocales [en, es, fr, de];if (in_array($locale, $availableLocales)) {App::setLocale($locale);}return $next($request);}}Laravel 内置的中间件Laravel 12 内置了一些强大的中间件来处理常见任务身份验证Authenticate确保用户已登录RedirectIfAuthenticated已登录用户访问登录页时自动跳转CSRF 保护VerifyCsrfToken防止 POST、PUT、PATCH 和 DELETE 请求的跨站请求伪造攻击Session 管理StartSession处理 Session 数据ShareErrorsFromSession把验证错误传递给视图Cookie 加密EncryptCookies自动加密解密 CookieAddQueuedCookiesToResponse把队列中的 Cookie 加入响应安全相关HandleCors处理跨域请求 (CORS)TrustProxies配置可信代理用于负载均衡场景维护模式PreventRequestsDuringMaintenance维护模式下阻止请求最佳实践跟着这些建议做可以让你的中间件更好维护、更安全、性能也更好保持简单专注一个中间件只做一件事。如果一个中间件做的事情太多就该拆分了// 坏例子一个中间件做太多事class HandleRequestMiddleware{public function handle($request, $next){// 认证// 验证// 日志// 转换数据// 等等...}}// 好例子拆分成多个中间件class AuthenticateMiddleware { }class ValidateRequestMiddleware { }class LogRequestMiddleware { }class TransformRequestMiddleware { }用参数提高灵活性让中间件接受参数能提高复用性// 不要创建 CheckAdminMiddleware、CheckModeratorMiddleware 等// 写一个灵活的就够了class CheckRole{public function handle($request, $next, ...$roles){if (! $request-user()-hasAnyRole($roles)) {abort(403);}return $next($request);}}// 使用方式Route::get(/admin, fn() ...)-middleware(role:admin);Route::get(/content, fn() ...)-middleware(role:admin,editor);注意执行顺序中间件的顺序很重要。认证中间件应该放在需要用户信息的中间件之前Route::middleware([auth, verified, role:admin])-group(function () {// 这里的路由});不要滥用不是所有逻辑都适合放在中间件里。中间件适合处理多个路由的通用逻辑。如果是特定路由的逻辑考虑用控制器方法表单请求验证类服务类路由模型绑定优化性能中间件逻辑要尽量轻量。如果有耗时操作用缓存避免重复计算把耗时任务放到队列用可终止中间件做响应后处理public function handle($request, $next){// 只做快速检查if (Cache::has(user-banned: . $request-user()-id)) {abort(403);}return $next($request);}public function terminate($request, $response){// 耗时操作放到响应后SomeHeavyJob::dispatch($request-user());}处理好异常中间件里要做好异常处理避免应用崩溃public function handle($request, $next){try {// 验证 Token$token $request-header(X-API-Token);$this-tokenService-validate($token);} catch (InvalidTokenException $e) {return response()-json([error Invalid token], 401);}return $next($request);}写测试给中间件写测试确保它们正常工作?phpnamespace Tests\Feature;use Tests\TestCase;class CheckAdminMiddlewareTest extends TestCase{public function test_non_admin_cannot_access_admin_routes(){$user User::factory()-create([role user]);$response $this-actingAs($user)-get(/admin/dashboard);$response-assertStatus(403);}public function test_admin_can_access_admin_routes(){$admin User::factory()-create([role admin]);$response $this-actingAs($admin)-get(/admin/dashboard);$response-assertStatus(200);}}加上类型声明用上 PHP 的类型系统IDE 也能更好地提示use Illuminate\Http\Request;use Symfony\Component\HttpFoundation\Response;public function handle(Request $request, Closure $next): Response{// 实现}注释要清楚如果中间件有参数记得加注释说明/*** 检查用户是否具有所需角色。** param \Illuminate\Http\Request $request* param \Closure $next* param string ...$roles 所需角色admin、editor、moderator* return \Symfony\Component\HttpFoundation\Response*/public function handle(Request $request, Closure $next, string ...$roles): Response{// 实现}安全相关中间件在应用安全中很关键。注意这几点别忘了 CSRF 保护Laravel 的 VerifyCsrfToken 中间件要加入 web 组用来保护所有修改数据的请求-withMiddleware(function ($middleware) {$middleware-appendToGroup(web, [\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class,]);})API Token 验证API 路由要做好 Token 验证public function handle($request, $next){$token $request-bearerToken();if (! $token || ! $this-isValidToken($token)) {return response()-json([error Unauthorized], 401);}return $next($request);}限流保护加上限流防止被恶意攻击特别是 API 和登录接口Route::middleware([throttle:60,1])-group(function () {// 每分钟最多 60 次请求});输入清理虽然 Laravel 已经有 CSRF 和 SQL 注入防护但在中间件里再加一层清理也不错public function handle($request, $next){$input $request-all();array_walk_recursive($input, function ($value) {if (is_string($value)) {$value htmlspecialchars($value, ENT_QUOTES, UTF-8);}});$request-merge($input);return $next($request);}敏感路由要保护好给敏感路由加多层中间件保护Route::middleware([auth, verified, 2fa, role:admin])-group(function () {// 敏感的管理后台路由});调试技巧如果中间件不正常试试这些方法启用查询日志public function handle($request, $next){DB::enableQueryLog();$response $next($request);Log::debug(Queries executed:, DB::getQueryLog());return $response;}记录执行日志public function handle($request, $next){Log::debug(Middleware executed: . static::class);return $next($request);}用 Telescope 调试Laravel Telescope 能帮你监控中间件执行、请求处理和性能指标。开发环境安装一下composer require laravel/telescope --devphp artisan telescope:installphp artisan migrate中间件 vs. 其他功能什么时候用中间件什么时候用其他特性看这里vs. Form Requests用中间件多个路由的通用逻辑用 Form Request单个路由的验证逻辑vs. Gates 和 Policies用中间件路由级别的权限检查用 Gates/Policies控制器里的资源权限检查vs. Service 类用中间件HTTP 请求/响应相关的操作用 Service 类跟 HTTP 无关的业务逻辑vs. Events 和 Listeners用中间件同步处理请求/响应用 Events/Listeners解耦的、可能异步的操作性能优化这些方法能提升中间件性能缓存耗时操作public function handle($request, $next){$userId $request-user()-id;$permissions Cache::remember(user-permissions:{$userId},3600,fn() $this-permissionService-getUserPermissions($userId));$request-merge([permissions $permissions]);return $next($request);}尽早返回不符合条件就赶紧返回别继续执行public function handle($request, $next){if (! $request-user()) {return redirect(/login);}if (! $request-user()-isActive()) {return response(Account suspended, 403);}return $next($request);}按需加载不要一开始就加载所有依赖用到再加载public function handle($request, $next){// 仅在需要时加载服务if ($request-has(validate)) {app(ValidationService::class)-validate($request);}return $next($request);}常见错误写中间件时避免这些坑忘记 return必须 return $next($request) 的结果// 错误public function handle($request, $next){if (! $request-user()) {redirect(/login); // 缺少 return}$next($request); // 缺少 return}// 正确public function handle($request, $next){if (! $request-user()) {return redirect(/login);}return $next($request);}在 $next 之后改请求调用 $next() 后再改请求已经没用了// 错误public function handle($request, $next){$response $next($request);$request-merge([foo bar]); // 已经晚了return $response;}// 正确public function handle($request, $next){$request-merge([foo bar]);return $next($request);}忘记注册用之前记得在 bootstrap/app.php 里注册。顺序错了注意顺序认证要放在权限检查之前// 错误的顺序Route::middleware([role:admin, auth])// 正确的顺序Route::middleware([auth, role:admin])从 Laravel 11 升级如果你是从 Laravel 11 升级来的中间件注册方式改了老写法Laravel 11protected $middleware [\App\Http\Middleware\TrustProxies::class,];protected $middlewareGroups [web [\App\Http\Middleware\EncryptCookies::class,],];protected $routeMiddleware [auth \App\Http\Middleware\Authenticate::class,];新写法Laravel 12-withMiddleware(function ($middleware) {// 全局 Middleware$middleware-append(\App\Http\Middleware\TrustProxies::class);// Middleware 组$middleware-appendToGroup(web, [\App\Http\Middleware\EncryptCookies::class,]);// 路由 Middleware 别名$middleware-alias([auth \App\Http\Middleware\Authenticate::class,]);})总结Laravel 中间件是个强大的特性能以干净、可复用的方式处理通用逻辑。掌握好中间件的用法和最佳实践就能写出更安全、更好维护、性能更好的 Laravel 应用。重点回顾中间件是 HTTP 请求的过滤器Laravel 12 把注册从 Kernel.php 移到了 bootstrap/app.php有全局、路由和组三种中间件中间件可以接收参数提高灵活性保持简单专注记得写测试适用于安全、日志、数据转换等通用场景注重性能、安全和可维护性随着使用的深入你会发现更多中间件的用法也会形成自己的实现模式。记住一点中间件要保持专注、逻辑清晰、文档齐全。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询