ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Laravel 11.x升级指南:目录瘦身、中间件新机制与迁移实战

Laravel 11.x升级指南:目录瘦身、中间件新机制与迁移实战 1. 先别急着升级Laravel 11.x到底改了什么底层逻辑如果这几天你在 Laravel 社区蹲过会发现一个很有意思的现象很多人拿到 11.x 的骨架项目后第一反应是“怎么这么干净”是的11.x 最大的变化不是多了一个炫酷的新功能而是它做了一场规模庞大的“减法手术”。这代版本把框架的默认配置、目录结构、依赖关系重新梳理了一遍底层逻辑从“开箱即用什么都给你”变成了“你需要的才会出现”。先说大家一定会遇到的硬门槛Laravel 11.x 要求 PHP 8.2 起步同时要求 PHPUnit 版本跟进到 10.5。换句话说如果你还在用 PHP 8.0 或 8.1即使你想尽办法绕过版本检查框架内部的语法特性也没法在旧版本上跑起来。这一点和 PHP 8.2 新增的动态类常量、只读类等特性强相关框架本身已经在用这些新语法写代码了所以升 PHP 是绕不过去的第一步。目录结构的精简其实才是 11.x 的“隐藏主角”。以前你 new 一个 Laravel 项目app/下面会默认生成Console、Exceptions、Http、Models、Providers这些目录。到了 11.x这一切被大幅压缩默认没有app/Console目录没有app/Exceptions目录app/Http/Middleware也不会预生成一堆中间件文件bootstrap/目录里多了一个app.php用来替代以往大量的config/app.php和Kernel.php。第一次看到这个结构的人会觉得“是不是安装出问题了”实际上这就是 Laravel 11 的设计目标让你需要扩展时才手动创建文件而不是先给一堆默认文件让你去删。这意味着什么对老项目升级来说这不是简单的改版本号而是要把原本依赖自动加载的类文件重新梳理。对新建项目来说写起来确实清爽不少但新手如果照着老教程找app/Http/Kernel.php一定找不到——这个文件在 11.x 里彻底消失了。2. 核心新特性拆解从目录瘦身到骨架重构成型2.1 中间件不再写在 Kernel而是直接链式注册以前我们定义中间件标准动作是打开app/Http/Kernel.php在$middleware和$middlewareGroups数组里手动注册。框架启动时会自动扫一遍然后按顺序执行。多了还要分web组、api组每次新增一个中间件都要在文件里找位置时间久了那个数组简直像杂货铺。11.x 把这一步改成“直接链式注册”。你不再需要一个全局的 Kernel 文件而是在路由文件里用-middleware()方法直接挂载。比如Route::middleware([auth, verified])-group(function () { Route::get(/dashboard, function () { return view(dashboard); }); });这个改动最直接的价值是中间件和路由的关联变得比以往任何时候都透明。你可以一眼看到某个路由组到底挂了哪些中间件不用再跳转到一个集中式 Kernel 文件里来回核对。对多人协作项目来说这段心智负担的减少非常明显。当然全局性中间件还是可以定义的只是姿势不同了——你需要在bootstrap/app.php里调用-withMiddleware()方法-withMiddleware(function (Middleware $middleware) { $middleware-web(append: [ EnsureUserIsSubscribed::class, ]); })我实测下来这种新方式对 API 项目的组织更友好但对一些已经习惯了 Kernel 集中管理的团队前期会有一点点适应成本。2.2 不再默认生成 Exception Handler异常处理逻辑迁入 bootstrap以前我们处理异常标准做法是编辑app/Exceptions/Handler.php在render()和report()方法里写各种判断。Laravel 11.x 把Handler整个拿掉了异常上报逻辑默认收敛到框架内部你不再需要继承一个 Handler 类去覆写方法。如果你有自定义异常处理需求可以直接在bootstrap/app.php里用-withExceptions()方法注册-withExceptions(function (Exceptions $exceptions) { $exceptions-shouldRenderJsonWhen(fn ($request, $e) $request-is(api/*)); })如果你确实需要完全接管异常渲染逻辑也可以创建自己的异常类或使用renderable方法注册闭包。这种“默认够用按需扩展”的思路完全贴合 Laravel 11 的整体设计理念。别小看这个改动很多老项目升级时遇到的第一个坑就是以前自己的业务逻辑大量依赖自定义 Handler 里的report()方法做日志写入升级后这份代码该往哪放我个人的建议是把日志上报逻辑拆成独立的 service在withExceptions里用闭包去调用而不是去硬新建一个 Handler 类把自己绑回去。2.3 配置文件大瘦身只有你改了才会用到 config 文件Laravel 11.x 的config目录默认只有app.php和database.php两个文件了不是官方偷懒而是框架把几乎所有配置项都收进了框架内部的默认值里。比如发送邮件的配置以前你要发布一份config/mail.php才能改 SMTP 参数现在可以直接在.env里写MAIL_MAILER、MAIL_HOST、MAIL_PORT然后直接跑。当你需要对某些默认配置做更细粒度的控制时再执行php artisan config:publish mail把对应文件发布出来改改完框架会自动合并覆盖。这个机制的背后是 Laravel 已经内置了一套完善的“配置即代码”默认值这些默认值能够覆盖绝大多数中小型项目的需求。对开发者而言最大的收益就是项目根目录清爽多了.env和默认配置足够应付大多数场景特殊场景再按需发布配置文件。这在容器化部署场景里尤其舒服因为镜像里不再需要为了一处 SMTP 配置去维护一整套配置文件了。2.4 路由文件调整api.php不再是默认生成项在 Laravel 10 及之前只要你装了项目routes/下面一定躺着web.php和api.php。11.x 默认只生成web.php如果你需要 API 路由需要自己执行php artisan install:api命令。这个改动表面上是“少了点东西”实际是在推动开发者在创建项目时就想清楚我做的到底是纯 Web 应用、纯 API 应用还是两者混合这个倾向在 11.x 里特别明显install:api不仅会帮你创建routes/api.php还会帮你装好 Sanctum 的 API 令牌认证相关配置虽然 Laravel 11 已经内置了 Sanctum但这命令会把对应脚手架也叫出来。我试过在新项目里直接跑php artisan install:api整个过程大概十几秒比较顺手。对 API 项目来说这样比手动创建文件省事得多。2.5 依赖精简PHPUnit 不再默认安装以前的 Laravel 骨架项目默认带着phpunit/phpunit就算你根本不想跑单元测试它也会乖乖躺在composer.json里。Laravel 11 把这部分依赖彻底拆了出去新建项目里不再默认装 PHPUnit只有当你执行composer require phpunit/phpunit --dev之后才有测试基础设施。类似的原先默认带上的mockery/mockery也不再是必须的了。这是一种很聪明的解耦方式核心框架依赖少了安装体积变小、composer 解析依赖的时间变短。实际体验中执行composer install的速度确实比 Laravel 10 时代快了不少。不过第一次接触的开发者可能会有点懵为什么php artisan test提示命令不存在你只要去查一下项目根目录有没有phpunit.xml文件就知道原因了——因为根本没安装。3. 升级实战记录从 Laravel 10 平滑迁移的完整链路这里分享一次真实的升级过程。手头项目是一个典型的单体应用用户系统、文章模块、支付回调、后台管理用了 Laravel 10 MySQL Redis代码量大概十几万行。由于要踩完所有常见的坑特地把升级路径记录下来。3.1 第一步PHP 8.2 检查与依赖版本梳理升级前先在本地跑一遍php -v确认 PHP 版本。如果你用的是 Laravel 官方 Homestead 或 Laravel Sail11.x 版本已经默认使用 PHP 8.2问题不大。如果你是直接用系统 PHP 的就要特别小心很多旧扩展可能没跟上比如php8.2-sqlite、php8.2-redis在部分发行版软件源里可能不叫这个名字。依赖梳理也很关键。Laravel 11 对第三方包的最低版本要求普遍提高了最明显的是spatie/laravel-permission、barryvdh/laravel-debugbar这类高频包。我当时是先把laravel/framework升级到^11.0试跑composer updateComposer 会直接告诉你哪些包版本冲突。这里有个很实用的技巧先升级laravel/framework本身再顺手执行composer update --with-all-dependencies让 Composer 自动把能兼容的包一并升上去比一个个手动指定版本高效得多。3.2 第二步处理 Kernel 文件移除带来的连锁反应Laravel 11 删掉了app/Http/Kernel.php之后如果你的应用里注册了很多自定义中间件就必须把它们迁移到bootstrap/app.php。我当时项目里有五六个全局中间件和三四个路由组中间件。第一步先看哪些中间件是可选的——auth、verified这类框架自带中间件不需要注册框架已经自动处理了。关键动作是把自定义中间件注册成“别名”然后通过路由链式调用。比如项目里有个CheckPermission中间件以前在 Kernel 里注册为permission CheckPermission::class现在改成在bootstrap/app.php的withMiddleware里写-withMiddleware(function (Middleware $middleware) { $middleware-alias([ permission \App\Http\Middleware\CheckPermission::class, ]); })然后路由里照旧-middleware(permission)外部调用方式不变但内部注册机制已经完全变了。迁移时最重要的是把所有Kernel.php里的别名和中间件分组全部核对清楚漏掉任何一个线上就会出现“你这个接口为什么没走权限验证”的诡异事故。3.3 第三步配置发布与 .env 对齐老项目的config目录是完整的升级到 11.x 之后这些配置文件并不会自动消失所以直接跑composer update本身不会报错。但问题在于Laravel 11 默认只加载config/app.php和config/database.php其他文件需要手动 publish 或者留在原地。好消息是原来的配置文件只要还在config目录下框架会自动加载合并不会报错。这里我踩了一个小坑Laravel 11 的config/app.php和旧版本的格式已经不一样了旧文件里经常写providers [...]、aliases [...]新版本全部默认内置。如果你把老配置文件整个覆盖过去反而可能出问题。我的经验是保留项目自定义配置比如config/mail.php、config/queue.php这些业务强相关的文件没问题但是config/app.php最好重新发布一份再手动补业务需要的自定义配置项避免骨架结构错位。3.4 第四步测试并修复异常处理逻辑因为异常 Handler 被移除我项目中很多依赖report()方法做错误通知的逻辑无法正常执行。比如支付回调失败时发送钉钉通知原本写在 Handler 的report()里。迁移后我把这段逻辑抽成了一个PaymentErrorReporter服务然后在bootstrap/app.php中通过withExceptions注册-withExceptions(function (Exceptions $exceptions) { $exceptions-report(function (PaymentException $e) { app(PaymentErrorReporter::class)-report($e); }); })这里要特别提醒withExceptions里的闭包注册顺序决定了异常处理的匹配优先级如果你的项目里对同一类异常有多个处理逻辑要注意顺序不是先注册的先执行而是框架内部按异常类型继承关系匹配的。实际测试时render()方法的改造压力也很大因为很多场景下我们希望 API 返回 JSON 格式的错误而不是 HTML 异常页。这个在 11.x 里可以用shouldRenderJsonWhen做全局控制比以前的写法干净很多。3.5 第五步路由与队列任务的全面回归升级完成之后不要急着上线先跑路由清单php artisan route:list。这一步能帮你直观看到所有路由是否正常尤其要注意中间件列的变化。我当时的项目里有一个路由组用了auth:apiguard在 11.x 下需要手动检查 Sanctum 的配置因为 Sanctum 的默认 guard 已经从web变成了api不对实际上 11.x 集成了 Sanctum 后默认配置已经内置在框架里了需要确认你的config/sanctum.php是否和框架默认值一致否则会出现令牌校验失效的问题。队列任务方面11.x 的handle()方法签名没有大的变化但如果你用了ShouldBeUnique或ShouldBeEncrypted这类接口建议仔细看升级文档。一个简单验证方法本地跑一轮测试队列php artisan queue:work --once观察是否有异常抛出来。整个升级过程我实际花了大半天时间。如果项目复杂度和我这个差不多建议至少留出一天来做回归别把升级压缩在上线前一小时。4. 新架构下的日常开发变化路由、健康检查与启动优化4.1 更加优雅的路由文件组织方式Laravel 11 对路由文件本身的处理也更聪明了。新的骨架里routes/web.php依然存在但是加载方式从原来的“扫描所有路由文件”变成了“在bootstrap/app.php里显式加载”。这意味着你可以决定哪些路由文件需要被加载哪些不需要甚至可以为不同子域名加载不同路由文件——这对中大型项目拆分模块太有帮助了。我在新项目里做出这样的结构主路由仍放web.php然后新增了routes/admin.php、routes/api/user.php并在bootstrap/app.php中显式挂载-withRouting( web: __DIR__./../routes/web.php, api: __DIR__./../routes/api.php, commands: __DIR__./../routes/console.php, then: function () { Route::middleware(web) -prefix(admin) -group(base_path(routes/admin.php)); }, )这种显式注册方式比以往“自动按文件名加载”更好控制排查问题的时候一眼就能看出某个路由是哪里挂载进来的。不过要提醒一下withRouting的api参数走的是apimiddleware如果你需要多个 API 前缀还是要自己建路由文件再手动加载。4.2 内置健康检查接口运维友好型变化以前做容器健康检查要么用第三方扩展包要么自己写一个/health路由检测数据库连接、缓存驱动状态等等。Laravel 11 把这个能力内置了默认提供了一个/_health接口需要在bootstrap/app.php中启用返回框架最基本的状态。我实际在 K8s 部署时用的是这个接口做存活探针非常方便。不过这里有一个需要留意的点默认健康检查接口粒度很粗只代表“框架本身活着”不代表数据库可用。如果你的业务对数据库依赖极强建议还是自己写一个细粒度的/health/ready接口主动DB::select(select 1)一次再检查 Redis 是否连通。我在生产环境里就是这么做的用 Laravel 11 内置接口做 liveness用自定义接口做 readiness效果很好。4.3 默认 SQLite 支持零配置起步Laravel 11 的默认数据库连接是 SQLite对你没看错。新建项目不再默认给你配置 MySQL而是用一个database/database.sqlite文件跑起来。这个改动对快速原型验证非常友好你 clone 一个项目下来不需要安装 MySQL只要touch database/database.sqlite再php artisan migrate就能跑出完整的数据结构。当然生产环境大家还是用 MySQL 或 Postgres这个默认设置不影响实际选型但它改变了开发体验团队协作时每个成员本地只需要一个 SQLite 文件连数据库服务都不用启动。我自己现在写小工具项目都直接用默认 SQLite省掉一堆环境配置的焦虑。直到需要上生产再切 MySQL。4.4 Graceful shutdown 机制让队列和 HTTP 一起优雅退出在 Laravel 10 以及更早版本如果我们的应用使用了php artisan serve或者队列经常要平滑退出的场景总是头疼怎么处理正在跑的请求。11.x 在这一块做了不少底层优化。graceful shutdown相关能力被内置到了 HTTP 服务器和队列进程中更准确地配合 Supervisor 或 K8s 的 SIGTERM 信号做退出。实测下来使用 Laravel 11 Octane 或原生php artisan serve关闭进程时不再强制中断而是在跑完当前请求之后退出去。这些改进看起来没有“新功能”那么显眼但对线上稳定性的提升是实打实的升级之后最直观的感受就是部署发布时旧进程不再出现一堆半途中断的请求。5. 安全视角Laravel 11 默认加固与新风险排查热词里很多人关心 Laravel 的安全漏洞比如之前讨论度很高的 CVE-2024-29291属于 SQL 注入类问题。Laravel 在 11.x 里做了不少默认安全加固但框架不是万能的你用新版本也得注意几个容易忽略的细节。5.1 SQL 注入风险的进一步收敛Laravel 的查询构造器本质上是 PDO 预处理但开发者很容易在使用DB::raw()、whereRaw()、orderByRaw()时把外部输入直接拼接进去从而绕过预处理机制。Laravel 11 依旧保留这些原生能力因为这给了开发者灵活度但安全责任也就落在使用者头上。我的实践是如果必须用whereRaw那所有插值都必须用第二个参数绑定绝不拼字符串。比如Model::whereRaw(price ?, [$request-input(min_price)]);这一点在 Laravel 11 和 Laravel 10 里没有区别但因为 11 对 PHP 版本要求高很多老程序员升级后容易把注意力全放在新特性上反而忽略这些核心安全习惯。5.2 默认加密与 Cookie 加固Laravel 11 默认把APP_KEY类型要求提高到 base64 编码的 32 字节密钥和之前实际没区别但做了一层更严格的形式验证。另外 Cookie 的序列化方式保持启用这意味着如果你在 Cookie 里放过多数据性能会受影响但安全性更好。说实话Cookie 序列化是把双刃剑它可以防篡改但也限制了你直接在客户端存数据的空间。我的建议是大型 token 或用户数据尽量走数据库或 JWT别堆 Cookie。5.3 依赖漏洞排查习惯Laravel 11 移除了一部分旧依赖也确实减少了攻击面但它并不代表零漏洞。建议把composer audit或第三方工具比如 Laravel 的enlightn加入到 CI 流程里每次提交自动扫一遍 composer.lock 的已知漏洞。这比出了事再排查高效得多。5.4 升级后必须检查的三个安全配置项APP_ENV与APP_DEBUG是否被正确设置线上绝不能APP_DEBUGtrueSESSION_DRIVER建议用database或redis不要用file且目录可写Sanctum 的stateful配置要结合项目域名的实际情况否则容易出现跨域认证异常这些不是 Laravel 11 独有的安全问题但每次大版本升级都是重新审视安全基线的好机会。6. 性能配置与扩展思路让 11.x 在新硬件上跑出更好成绩6.1 懒加载和延迟绑定的默认优化Laravel 11 对模型懒加载的机制做了一次内部完善配合 PHP 8.2 的只读类特性模型属性访问的性能开销比之前更小。实际项目里如果你一贯使用with()预加载并合理控制select字段升级后接口响应速度会有小幅改善。如果出现 N1 查询Laravel 11 的Model::preventLazyLoading()依然有效建议在开发环境强制开启直接在日志里把所有懒加载模型调用全部打印出来从源头杜绝经典性能杀手。6.2 配合 Octane 使用常驻内存下的新特性适配Laravel 11 和 Octane 的配合是现在部署高性能应用的主流选择。常驻内存模式下bootstrap/app.php里的闭包逻辑会在每次请求时重新执行因此要注意不能让闭包捕获外部不断变化的状态。一个常见的坑是把配置值放进withRouting闭包里然后热重载时看到路由列表一直叠加。解决方式很简单路由加载闭包里只放静态注册逻辑不要做动态条件判断。用 Octane 跑 Laravel 11建议把队列和调度也统一走 Octane 进程这样整体进程模型简单很多。实际流量压测中响应时间普遍比传统 PHP-FPM 降低一半以上不过这是 Octane 本身的功劳和 Laravel 11 的关系不大。但 11 的骨架精简确实让我在配置 Octane 时少了很多干扰项比如旧的 Kernel 中间件机制在 Octane 下可能有状态残留现在中间件走路由链式注册反而更不容易出问题。6.3 队列与调度系统的新默认Laravel 11 把队列和调度的定义也从固定目录中拿了出来。以前你用app/Console/Kernel.php写定时任务现在直接在routes/console.php里用闭包或类定义Artisan::command(report:send, function () { // 业务逻辑 })-describe(发送运营日报)-dailyAt(09:00);机器可读的命令列表可以用php artisan list查看调度系统在执行时也能自动正确识别。这种改动让命令和调度注册变得更加灵活但如果你习惯旧项目把所有命令集中在一个文件里管理现在更推荐把命令独立成类放到app/Console/Commands并注册到routes/console.php里保持结构清晰。6.4 数据库迁移性能优化Laravel 11 内部对 schema 操作的性能做了调整。最简单的一个例子是新增字段到已有大表时底层执行方式更接近数据库原生支持的ADD COLUMN IF NOT EXISTS避免了一些中间步骤的缓慢锁表操作。实际执行php artisan migrate时如果数据库很大建议开启--pretend先看一遍 SQL避免意外生成重量级索引迁移。我就在一次迁移里用--pretend发现框架生成的索引比预想的多一个提前改了迁移文件才避免线上锁表风险。7. 实操总结我的建议与踩坑后的个人体会如果你正在规划升级 Laravel 11.x我的核心建议是先新建一个最小的 11.x 骨架项目把你要用的第三方包全部装上去试跑一遍确认没有依赖冲突再动老项目。老项目升级时不要奢望通过改版本号一步到位老老实实走一次手工迁移流程把所有 Kernel 相关逻辑、异常处理逻辑、配置发布逻辑全部梳理清楚。这个过程看似繁琐但是能让你彻底搞懂 11.x 新的骨架结构以后再接手任何 Laravel 11 项目都会非常顺利。还有一个小建议升级之后把原先老项目里没用的config文件、app/Console、app/Exceptions等目录清理干净不要“虽然不用了但留着以防万一”。Laravel 11 的新架构本来就是为了减少默认文件的冗余你把老文件还挂在那里反而容易让后续维护者分不清哪些是框架默认的、哪些是项目自定义的。总的来说Laravel 11.x 是新老划代的一次重要迭代它没有大量增加新功能而是在开发体验、底层架构、默认安全、启动性能上做了一次全面收拢。用习惯之后你再回头看 Laravel 10 的骨架会有一种“原来以前有那么多不需要存在的文件”的感叹。就我个人来说Laravel 11.x 最值得点赞的还是配置与中间件体系的收敛。以前项目规模一大Kernel.php和Handler.php两个文件动辄几百行很多逻辑交叉在一起看着就头疼。现在你需要的逻辑全部通过bootstrap/app.php显式表达整个应用的请求链路一目了然。作为经常要在老项目和新项目之间切换的人这种一目了然的感觉真的很珍贵。
返回列表