关于laravel6 路由分割后,路由缓存无效的问题?

关于laravel6 路由分割后,路由缓存无效的问题?

如图,我将routes/web.php分割为web目录下的多个文件,在我执行

php artisan route:cache 

之前,这些路由均正常访问,但在我执行完上面这个缓存命令后,就出现找不到路由的情况,在执行完下面这个路由缓存清理命令后,又恢复正常。

php artisan route:clear

请问,如果我想将路由分割,又想路由缓存的话,应该怎么做呢?

《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
最佳答案

解决方案

关键点在 require_once 上,你需要改为 require 才可以。

原因

因为在执行php artisan route:cache的时候,会进行两遍容器的启动:第一次是 artisan 命令自身需要启动一次容器,第二次是 route:cache 这个命令类中手动获取了一个新的容器实例,关键代码在这里:

<?php

namespace Illuminate\Foundation\Console;

class RouteCacheCommand extends Command
{
    protected $name = 'route:cache';
    ...
    /**
     * Get a fresh application instance.
     *
     * @return \Illuminate\Contracts\Foundation\Application
     */
    protected function getFreshApplication()
    {
        // 注释写的很清楚了,这里重新获取一个新的容器实例
        return tap(require $this->laravel->bootstrapPath().'/app.php', function ($app) {
            $app->make(ConsoleKernelContract::class)->bootstrap();
        });
    }

如果你用require_once的话,那么第二次获取新的容器实例,就不会再加载你的文件了。而缓存就是根据第二次新的容器实例中的路由进行缓存的。第二次没有加载你的路由,就不会生成缓存。道理就是这样。

对比实验

按照你的代码,将 require 改回 require_once 后,把原框架中 获取新容器 实例的方法改为 获取当前第一次 初始化的容器,进行对比:

    protected function getFreshApplication()
    {
        return app();
        // return tap(require $this->laravel->bootstrapPath().'/app.php', function ($app) {
        //     $app->make(ConsoleKernelContract::class)->bootstrap();
        // });
    }

此时再次执行php artisan route:cache是可以生成缓存的。

缓存后的路由在这里routes-v7.php,我的是 Laravel 8:

Laravel

3年前 评论
JerryBool 3年前
讨论数量: 11

请问解决了么?

3年前 评论

@return 还没有,目前就是路由不缓存

3年前 评论

解决方案

关键点在 require_once 上,你需要改为 require 才可以。

原因

因为在执行php artisan route:cache的时候,会进行两遍容器的启动:第一次是 artisan 命令自身需要启动一次容器,第二次是 route:cache 这个命令类中手动获取了一个新的容器实例,关键代码在这里:

<?php

namespace Illuminate\Foundation\Console;

class RouteCacheCommand extends Command
{
    protected $name = 'route:cache';
    ...
    /**
     * Get a fresh application instance.
     *
     * @return \Illuminate\Contracts\Foundation\Application
     */
    protected function getFreshApplication()
    {
        // 注释写的很清楚了,这里重新获取一个新的容器实例
        return tap(require $this->laravel->bootstrapPath().'/app.php', function ($app) {
            $app->make(ConsoleKernelContract::class)->bootstrap();
        });
    }

如果你用require_once的话,那么第二次获取新的容器实例,就不会再加载你的文件了。而缓存就是根据第二次新的容器实例中的路由进行缓存的。第二次没有加载你的路由,就不会生成缓存。道理就是这样。

对比实验

按照你的代码,将 require 改回 require_once 后,把原框架中 获取新容器 实例的方法改为 获取当前第一次 初始化的容器,进行对比:

    protected function getFreshApplication()
    {
        return app();
        // return tap(require $this->laravel->bootstrapPath().'/app.php', function ($app) {
        //     $app->make(ConsoleKernelContract::class)->bootstrap();
        // });
    }

此时再次执行php artisan route:cache是可以生成缓存的。

缓存后的路由在这里routes-v7.php,我的是 Laravel 8:

Laravel

3年前 评论
JerryBool 3年前

@LiamHao 这不影响,我传入目录也会返回那个目录的,base_path是项目目录的意思,也可以传入目录

3年前 评论

@acehua 楼上回复已更新。亲测可用

3年前 评论

@LiamHao 万分感谢,我现在还没法测试可行性,等我测试完,我再给答案。先问个问题,我那样写不行的原因难道是group如果第一个参数为数组,那么第二个参数就必须是文件?

3年前 评论
LiamHao 3年前

@LiamHao 请问有测试过我那个写法么?那require_once不行的原因是什么呢?抱歉,我目前还没办法测试改为require_once的可行性

3年前 评论
LiamHao 3年前

@LiamHao 谢谢大佬费时解惑

3年前 评论

Route::group([],base_path('route_file'));

3年前 评论

@陈先生 已经选出答案了。你说的这个不是问题的关键哦,亲测成功

3年前 评论

@return 已经解决了,亲测可用,已经选出答案,改为require就可以了

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!