Cài đặt zend-stratigility
zend-stratigility là nền tảng để xây dựng ứng dụng MiddleWare theo chuẩn PSR-7. zend-stratigility tạo ra cơ chế pipeline, để chứa và thi thành các MiddleWare theo nguyên tắc của nó. Ví nó sử dụng zend-diactoros chính là thư viện triển khai chuẩn PSR - 7, nên khi cài đặt Statigility, bạn cũng cần cài cả Diactoros.
Nếu tự tích hợp vào dự án, tải về các thành phần và gộp vào dự án theo địa chỉ:
Để cài đặt chuẩn và nhanh chóng hãy sử dụng composer bằng câu lệnh:
composer require zendframework/zend-diactoros zendframework/zend-stratigility
Sử dụng cách thứ 2 để cài đặt thư viện này, giả sử tạo thư mục dự án là: stratigility và có thể chạy website bằng đường dẫn
như http://localhost/stratigility/
. Vào thư mục tạo ra đó, và gõ lệnh composer trên tải thư viện về.
Tạo file index.php
(đây là nơi thực hành code các ví dụ đơn giản của bài viết này) trong thư mục dự án với nội dung như sau:
<?php require __DIR__ . '/vendor/autoload.php';
Ngoài ra để đảm bảo các URL gọi đến đều chạy file index.php
thì có thể tạo file .htaccess
ở thư mục gốc dự án với nội dung
RewriteEngine On # Cho phép Apache trả về nội dung file yêu cầu nếu tồn tại (image, css, js ...) RewriteCond %{REQUEST_FILENAME} -s [OR] RewriteCond %{REQUEST_FILENAME} -l [OR] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^.*$ - [NC,L] #Các truy vấn khác sẽ gọi đến index.php RewriteCond %{REQUEST_URI}::$1 ^(/.+)(.+)::\2$ RewriteRule ^(.*) - [E=BASE:%1] RewriteRule ^(.*)$ %{ENV:BASE}index.php [NC,L]
Tạo ứng dụng Middleware
Middleware là code nằm giữa request
và response
(đọc PSR-7 để biết chi tiết về Request và Response),
nó nhận request gửi đến, thi hành các tác vụ, cuối cùng nó cần phải trả về response hoặc thi hành Middleware phía sau nó trong hàng đợi pipeline.
Một ứng dụng Middleware PSR-7, đơn giản thì cần phải tạo các thành phần:
- Tạo đối tượng
Zend\Stratigility\MiddlewarePipe
là pileline, nó dùng để chứa các Middleware theo thứ tự. Middleware gắn vào nó bằng phương thứcpipe()
- Tạo đối tượng
Zend\Diactoros\Server
nhận các thông tinHTTP requests
rồi chuyển nó đến một callback (chính là MiddlewarePipe), sau đó gửi Response cho Client. ĐểZend\Diactoros\Server
nhận các Request gửi đến cần gọi phương thứclisten
Giờ thực hành, cập nhật index.php
như sau:
<?php require __DIR__ . '/vendor/autoload.php'; use Zend\Stratigility\MiddlewarePipe; use Zend\Diactoros\Server; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; $app = new MiddlewarePipe(); $app->setResponsePrototype(new Response()); $homePage = function (ServerRequest $req, Response $res, $next) { $res->getBody()->write('MiddleWare Homepage'); return $res; }; $detailPage = function (ServerRequest $req, Response $res, $next) { $res->getBody()->write('MiddleWare Detail'); return $res; }; $app->pipe('/stratigility/detail', $detailPage); $app->pipe('/stratigility/home', $homePage); $app->pipe(new \Zend\Stratigility\Middleware\NotFoundHandler(new Response())); $server = Server::createServer($app, $_SERVER, $_GET, $_POST, $_COOKIE, $_FILES); $server->listen(new \Zend\Stratigility\NoopFinalHandler());
Hãy chạy thử kiểm tra code trên với các URL: http://localhost/stratigility/home, http://localhost/stratigility/detail, http://localhost/stratigility/xyz ...
Giải thích code ứng dụng với Middleware ở trên
$app là đối tượng MiddlewarePipe, nó chứa các Middleware mà bạn tạo ra trong hệ thống.
$homePage, $detailPage là Middleware, 2 Middleware ở ví dụ này bạn tạo ra
theo cấu trúc closure
với các tham số theo mẫu:
<?php function (ServerRequest $req, Response $res, $next) { //$req - yêu cầu nhận được //$res - đối tượng Response //$next - Middleware phía sau trong pileline //... //.. };
Các Middleware được gắn vào Pile bằng phương thức pipe($path, $middleware)
, như code trên là đoạn:
$app->pipe('/stratigility/detail', $detailPage); $app->pipe('/stratigility/home', $homePage); $app->pipe(new \Zend\Stratigility\Middleware\NotFoundHandler(new Response()));
Trong đó tham số $path
là đường dẫn. Ví dụ URL là /stratigility/home
thì sẽ gọi ngay đến $homePage
,
bạn nhớ là các đường dẫn con cũng sẽ gọi đến Middleware tương ứng. Ví dụ như /stratigility/home/1
, /stratigility/home/2/3
...
đều dẫn tới Middleware $homePage.
Nếu phương thức pipe()
chỉ nhận một tham số, thì tham số đó là Middleware, và Middleware đó sẽ có thể được gọi với mọi đường dẫn (Request).
Như trường hợp trên:
$app->pipe(new \Zend\Stratigility\Middleware\NotFoundHandler(new Response()));
Cuối cùng tạo Server và lắng nghe các yêu cầu gửi đến, và hệ thống sẽ gọi các Middleware tướng để thi hành.
$server = Server::createServer($app, $_SERVER, $_GET, $_POST, $_COOKIE, $_FILES); $server->listen(new \Zend\Stratigility\NoopFinalHandler());
Khi ứng dụng Middleware nhận các Request, thì MiddlewarePipe sẽ phân tích đường dẫn và gọi đến Middleware phù hợp trong hàng đợi các Middleware, Middleware có thể trả về Response để Zend\Diactoros\Server gửi về cho client và kết thúc hoặc gọi đến Middleware kế tiếp trong hàng đợi qua tham số $next
Tạo Middleware bằng cách triển khai giao diện MiddlewareInterface
Ngoài cách sử dụng closure
để tạo ra Middleware như trên, còn có thể tạo ra các lớp định nghĩa Middleware bằng cách triển khai giao diện
Interop\Http\Server\MiddlewareInterface
và định nghĩa phương thức process
trả về Response phù hợp.
Ví dụ sử file index.php
trên thành:
<?php require __DIR__ . '/vendor/autoload.php'; use Zend\Stratigility\MiddlewarePipe; use Zend\Diactoros\Server; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; class FirstMiddleware implements \Interop\Http\Server\MiddlewareInterface { public function process( \Psr\Http\Message\ServerRequestInterface $request, \Interop\Http\Server\RequestHandlerInterface $handler) { /* * Nếu muốn gọi Middleware kế tiếp * return $handler->process($request); * * trả về Response mặc định: * $res = new Response(); * $res * ->withStatus(200) * ->withHeader('Content-Type', 'text/plain; charset=utf-8' ) * ->getBody()->write('Test My First Middleware'); * * trả về JSON * $data = ['message' => 'JSON RESPONSE']; * return new Response\JsonResponse($data); * * Trả về HTML * return new Response\HtmlResponse('HTML Response'); * * Trả về chuyển hướng * return new Response\RedirectResponse( * new \Zend\Diactoros\Uri('http://google.com.vn'), 301); */ return new Response\TextResponse('Test My First Middleware'); } } $app = new MiddlewarePipe(); $app->setResponsePrototype(new Response()); $homePage = function (ServerRequest $req, Response $res, $next) { $res->getBody()->write('MiddleWare Homepage'); return $res; }; $detailPage = function (ServerRequest $req, Response $res, $next) { $res->getBody()->write('MiddleWare Detail'); return $res; }; $app->pipe('/stratigility/detail', $detailPage); $app->pipe('/stratigility/home', $homePage); $app->pipe('/stratigility/first', new FirstMiddleware()); $app->pipe(new \Zend\Stratigility\Middleware\NotFoundHandler(new Response())); $server = Server::createServer($app, $_SERVER, $_GET, $_POST, $_COOKIE, $_FILES); $server->listen(new \Zend\Stratigility\NoopFinalHandler());
Kiểm tra với http://localhost/stratigility/first
để Middleware: FirstMiddleware được thi hành
NotFoundHandler - Middleware bắt lỗi 404
Ở ví dụ trên, đã sử dụng Middleware có sẵn là Zend\Stratigility\Middleware\NotFoundHandler
,
Middleware này đặt ở cuối hàng đợi pileline, khi tất cả các đường dẫn không phù hợp thì gọi đến Middleware này để trả về báo lỗi 404.
NotFoundHandler - Middleware bắt lỗi 404
Ở ví dụ trên, đã sử dụng Middleware có sẵn là Zend\Stratigility\Middleware\NotFoundHandler
,
Middleware này đặt ở cuối hàng đợi pileline, khi tất cả các đường dẫn không phù hợp thì gọi đến Middleware này để trả về báo lỗi 404.
ErrorHandler
Middleware ErrorHandler để bắt các Exception / Error trong ứng dựng, để đăng ký dùng code như sau:
$app->pipe( new \Zend\Stratigility\Middleware\ErrorHandler(new Response(), new \Zend\Stratigility\Middleware\ErrorResponseGenerator(true)));
Để bắt các lỗi bạn nhớ nó phải là lớp ngoài cùng của Middleware, nghĩa là phải pipe đầu tiên. Giờ ở Middleware nào đó thử phát sinh throw new Exception('Test');
để kiểm tra lỗi bắt được.