【BUG】 action-hook插件 被提前在【中间件】之前执行

admin

bug描述

我还是希望群主能想办法,把这个action-hook应该改为 全局中间件->用户应用中间件->路由中间件-> action-hook中间件->控制器的某个方法,就想__consturct一样,但是我又不想 关闭 控制器复用模式,

程序代码或配置

config/middleware.php

<?php
return [
    '' => [
        \app\middleware\AccessOptionRequestMiddleware::class
    ],
    'app_admin'=>[
        \app\app_admin\MiddlewareAppAdmin::class
    ],
    'app_user'=>[
        \app\app_user\MiddlewareAppUser::class
    ],
];

MiddlewareAppAdmin.php

<?php

namespace app\app_admin;

use app\api\service\JwtService;
use app\api\service\ResponseJson;
use app\ConstMap\HttpStatusConst;
use app\ConstMap\JwtConst;
use Webman\Http\Request;
use Webman\Http\Response;
use Webman\MiddlewareInterface;

class MiddlewareAppAdmin implements MiddlewareInterface
{

    public function process(Request $request, callable $handler): Response
    {

        return \response('不执行这里');
    }
}

controller.php

<?php

namespace app\app_admin\controller;

use app\model\Recharge;
use app\model\Users;
use support\Request;
use Webman\View;

class AdminDashboard
{

    public function beforeAction(Request $request){

        var_dump('111');
//        \support\View::assign('username',Users::where('uid',$request->jwt->uid)->value('username'));
    }
}

执行顺序

var_dump(111);
\response('不执行这里');

系统环境及workerman/webman等具体版本

docker

952 1 0
1个回答

six

截图
你会不会url访问错了?

  • admin 2023-02-09

    我已经找到原因了,因为 action-hook插件会注册,全局中间件,我自己的应用中间件是后执行的,应用中间件里我加了$request->jwt 变量传递,action-hook先执行 public function beforeAction当然就报错了。

    我还是希望群主能想办法,把这个action-hook应该改为 全局中间件->用户应用中间件->路由中间件-> action-hook中间件->控制器的某个方法,就想__consturct一样,但是我又不想 开启 控制器复用模式

  • walkor 2023-02-09

    action-hook插件时为了解决控制器复用时__consturct无法执行问题。目前webman已经支持关闭复用控制器了,action-hook已经不推荐用了,推荐关闭控制器复用,使用__consturct。
    为了给过时的action-hook插件开绿灯更改内核不是好主意。

  • admin 2023-02-09

    如果关闭了复用控制器,会导致 每次都new std(),因为静态变量持久化内存的特性,现在的代码都是把一些 从数据库读取的信息 永久储存在 控制器静态变量中。

    目前我手动在/config/action-hook/app.php 中关闭了enable,并且人工在 /config/middleware.php中注册顺序。

    我目前就是有个疑问,在composer install的时候,会不会更改或覆盖 /config/action-hook/app.php 文件

  • walkor 2023-02-09

    composer install 不会更改config/plugin中已经存在的配置

  • oscar 2023-02-16

    @admin 我后来升级到最新,也是想关闭控制器复用,碰到的问题和你一样,所以还是用action-hook。同时,我想问一下,假如,两4个进程,是不是就有4个控制器常驻内存?也就是控制器里的静态变量也有四份?

  • 喵了个咪 2023-02-16

    需要持久保存的数据放在静态属性里,然后关闭控制器复用。这样即持久化保存了数据,又能每个请求自动调用__construct()初始化控制器实例。控制器静态属性保存数据和关闭控制器复用没有冲突。

  • 喵了个咪 2023-02-16

    @oscar 4个进程完全独立的,互相不影响,每个进程有自己的常住内存控制器,静态变量也是四份

  • ichynul 2023-02-16

    控制器复用,直接取消了更好。
    复用的时候需要在请求结束处理里面的用户数据,省内存和避免程序bug导致数据被下一个用户拿到。
    但是如果复用但是不在里面存数据,那复用也没多大用,就是节省了new 的开销。

  • 喵了个咪 2023-02-16

    开启控制器复用,控制器里面可以存一些公共数据,公共数据不需要请求结束时处理,这样没任何问题。
    如果需要控制器存当前请求状态数据,每次请求后需要清理,所以这种情况还是不开的好。

    不要小看这个new开销,关闭控制器复用,helloworld压力测试QPS降低20-30%左右,带数据库业务性能降低10%左右。

  • ichynul 2023-02-16

    公共数据没必要存控制器,单独弄一个类,搞静态属性。不然浪费内存,每个控制器4份,然后几十上百个控制器。
    除非所谓的公共数据是每个控制器独有的。

  • admin 2023-02-17

    公共数据没必要存控制器,单独弄一个类,搞静态属性。不然浪费内存,每个控制器4份,然后几十上百个控制器。

    难道 你单独的静态类 不是4份? 不是每个进程一份?难道是每个进程用同一份?那怎么没做锁呢

  • ichynul 2023-02-17

    区别就是单独放一个类里,几个进程就几份。你放控制器里,这个数字还要再乘以你的控制器数量。

  • admin 2023-02-17

    控制器默认是复用的不会出现你说的情况,即控制器::$StaticVal

  • ichynul 2023-02-17

    你说的是静态属性,那挂任何类上都是一样的,包括控制器。既然是静态属性,就跟new不new无关。

    protected static $Val1;//静态属性 份数=进程数,new无关,复用与不复用无区别
    protected $Val2;//非静态属性 份数=进程*控制器数,new相关,复用与不复用有区别
  • ichynul 2023-02-17

    @喵了个咪
    不要小看这个new开销,关闭控制器复用,helloworld压力测试QPS降低20-30%左右,带数据库业务性能降低10%左右。
    说实在的,一个框架里面要new的东西估计有点多。
    如果new一个控制器就有那么大影响,那真的是应该都用静态方法了,这样就不需要new。
    设想一下,假如开了控制复用,控制器里面有个helloworld方法。

    public function helloworld()
    {
         $servcice =new \app\common\helloworldService;
         $response = $servcice->doSomething();
         return $response;
    }

    你看,开启复用了,但是每次执行都new 了一个\app\common\helloworldService来处理请求,可能我在doSomething里面有new了一堆其他东西。
    所以new控制器节省的那点性能,是真实的吗?估计你的测试就是 return 'helloworld'吧。
    除非你要求程序员处理请求的过程中不要new 任何东西,我觉得不现实。


    好吧,我把helloworldService弄成静态属性了,这样就不用每次都new一次了。

    protected static $servcice;
    
    public function __construct()
    {
         $this->servcice =new \app\common\helloworldService;
    }
    public function helloworld()
    {
         $response = $this->servcice->doSomething();
         return $response;
    }

    但是doSomething仍然不是静态的呀,万一在里面new了其他东西呢?
    把helloworldService的doSomething也搞静态化?


    所以还是那句话:
    除非你要求程序员处理请求的过程中不要new 任何东西,我觉得不现实。这个要求有点过分!

  • ichynul 2023-02-18

    @喵了个咪
    你节省的new控制器的那点开销,只要后面过程中有任何一个new,就被抵消了。
    就算你写的代码全程静态方法静态属性,复用控制器以后不需要重复new任何东西。
    但是你不使用composer的东西吗?
    第三方库里面也许会给你new个东西出来吧!
    哈哈,气不气呀。
    所以我觉得这个框架节省的应该是类加载的开销,而不是new的开销。

  • 喵了个咪 2023-02-18

    我上面表达的观点是站在框架角度,不要小看这个new开销。当然你站在分业务角度,多一个new确实所谓。
    关闭控制器复用,webman可以做到一个请求几乎不new任何东西的。
    大部分业务中节省一个new确实没意义,但是站在框架角度,框架因节省一个new将极限性能提升20-30%意义很大
    所以webman框架应该支持控制器复用的功能,你可以关闭它不用,但是不能像你说的直接取消它。

  • ichynul 2023-02-18
    class Somecontroller
    {
        protected $thing2;
        protected static $thing3;
    
        public function __construct()
        {
            $this->thing2 = new someThing;
            if (!static::$thing3) {
                static::$thing3 = new someThing;
            }
        }
    
        public function someFunctin()
        {
            //方式1,直接new,每次调用此方法都重新new
            $thing1 = new someThing;
            $response = $thing1->someFunctin();
    
            //方式2,内部属性,不用每次都new。
            $response = $this->thing2->someFunctin();
    
            //方式3,静态属性,不用每次都new。
            $response = static::$thing3->someFunctin();
    
            //方式4,使用容器生产实例,应该和3等效吧
            $response = $container->make(someThing::class)->someFunctin();
    
            return $response;
        }
    }
    
    class SomeThing
    {
        public function someFunctin()
        {
            //这里用需要用到SomeThing2的someFunctin2
            //和上面类似
        }
    }
    
    class SomeThing2
    {
        public function someFunctin2()
        {
            //这里用需要用到SomeThing3的someFunctin3
            //和上面类似
        }
    }
    
    class SomeThing3
    {
        public function someFunctin3()
        {
            //这里用需要用到SomeThing4的someFunctin4
            //和上面类似
        }
    }
    class SomeThing4
    {
        //1个请求用到3~4个类不夸张吧
        public function someFunctin4()
        {
            //这里使用了一个composer的东西,超出控制范围了,它里面可能new了什么东西,我不可能去改它
        }
    }

    整个流程中的几次方法调用,能做到保持相同的姿势,不使用[方式1]?

  • 喵了个咪 2023-02-18

    我再重申一遍,我是站在框架角度,框架支持控制器复用减少一次new调用能让框架极限性能提升20-30%,对于框架而言是值得的,它能提升框架性能上限,不能像你说的取消支持控制器复用功能,我只是表达这个观点。

    至于你自己的业务怎么怎么调用,不在我的讨论范畴。

  • ichynul 2023-02-18

    站在框架的角度,不能只看到性能的提升。
    框架底层逻辑是有的区别,这是可能会产生一些差异的,不能只看到是性能的差异。
    在未开启控制器复用的情况下,如果安装了action-hook插件,是会拖慢性能的。
    当然,现在修复了,未开启控制器复用但安装了action-hook,不会生效而已也不拖性能。
    https://github.com/webman-php/action-hook/pull/2
    你要觉得我在装逼,那也没办法。

  • admin 2023-02-20

    你们不要再打了

年代过于久远,无法发表回答
🔝