首页 > 解决方案 > 添加中间件时执行两次动作 Slim 框架

问题描述

我正在基于优秀的 Slim 4 教程https://odan.github.io/2019/11/05/slim4-tutorial.html构建一个简单的应用程序

结构仍然与教程非常相似。

每次我使用 Postman 调用我的任何端点时,它都会为 Get 执行两次我的操作(即:\App\Action\UserGetAction)。我可以在我的日志中确认这正在发生。

如果我注释掉 config/middleware.php 中的 AuthMiddleware 文件,则重复操作将停止发生。

有任何想法吗?

我创建了自己的 Auth 中间件并将其添加到 config/middleware.php 文件中:

use Selective\BasePath\BasePathMiddleware;
use Slim\App;
use Slim\Middleware\ErrorMiddleware;
use SlimSession\Helper;
use App\Factory\SessionFactory;
use App\Factory\AuthMiddleware;

return function (App $app) {
    // Parse json, form data and xml
    $app->addBodyParsingMiddleware();

    // Add the Slim built-in routing middleware
    $app->addRoutingMiddleware();

    $app->add(BasePathMiddleware::class); 

    // Catch exceptions and errors
    $app->add(ErrorMiddleware::class);

    $app->add(AuthMiddleware::class); // <--- here
  
    $loggerFactory = $app->getContainer()->get(\App\Factory\LoggerFactory::class);
    $logger = $loggerFactory->addFileHandler('error.log')->createInstance('error');

    $errorMiddleware = $app->addErrorMiddleware(true, true, true, $logger);

};

为简单起见,我已经删除了 AuthMiddleware 中的几乎所有内容:

namespace App\Factory;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Slim\Psr7\Response;
use GuzzleHttp\Client;
use Exception;
use App\Factory\LoggerFactory;



class AuthMiddleware
{


  /**
    * @var LoggerInterface
    */
   private $logger;

  public function __construct(LoggerFactory $logger)
  {
      $this->logger = $logger
            ->addFileHandler('user_edit.log')
            ->addConsoleHandler()
            ->createInstance('user_edit');
  }




    /**
     * Example middleware invokable class
     *
     * @param  ServerRequest  $request PSR-7 request
     * @param  RequestHandler $handler PSR-15 request handler
     *
     * @return Response
     */




    public function __invoke(Request $request, RequestHandler $handler): Response
    {


        $response = $handler->handle($request);
        $headers = $request->getHeaders();


        $eauth = $headers["Authorization"][0];

        $this->logger->info($eauth);




        return $handler->handle($request);


    }




} //Class

这是我在 config/routes.php 中的路线:

    $app->post('/users', \App\Action\UserCreateAction::class);
    $app->map(['PUT', 'PATCH'],'/users/{id}[/{system}]', \App\Action\UserUpdateAction::class);
    $app->delete('/users/{id}[/{system}]', \App\Action\UserDeleteAction::class);
    $app->get('/users/{id}[/{system}]', \App\Action\UserGetAction::class);
    $app->get('/extid/{id}[/{system}]', \App\Action\ExtidGetAction::class);

我已经确认我只运行 $app-run() 一次 --- 在我的 index.php 末尾

require __DIR__ . '/../config/bootstrap.php';

$app->run();

标签: phproutesslim

解决方案


__invoke您的中间件方法有错误。

您两次调用处理程序队列:

public function __invoke(Request $request, RequestHandler $handler): Response
{
    // here you call handler queue first time
    // so you get response
    $response = $handler->handle($request); 
    $headers = $request->getHeaders();

    $eauth = $headers["Authorization"][0];

    $this->logger->info($eauth);

    // here you call handle queue for the second time 
    // so you get the second duplicated version of response
    // this is the reason why you actions called twice
    return $handler->handle($request);
}

解决方案之一如下:

public function __invoke(Request $request, RequestHandler $handler): Response
{
    // here you call handler queue first time
    // so you get response
    $response = $handler->handle($request); 
    $headers = $request->getHeaders();

    $eauth = $headers["Authorization"][0];

    $this->logger->info($eauth);

    // return response you already have
    return $response;
}

推荐阅读