快速入门
本章提供一个简单有趣的实践案例,构建一个最小化的应用程序,并对 Fluff 的中的概念做一个基本介绍。我们假设你已经安装好了 Fluff 2.0
,如果还没有,请先移步欢迎页面完成安装。
我们的案例中还需要用到 PSR-17 Factory 去生成 PSR-7 Server Request, 这里我选择了 nyholm/psr7-server
,当然,你也可以选择任何你喜欢的组件。
composer require nyholm/psr7 nyholm/psr7-server
由于我们需要一个 PSR-7 Server Request 作为请求载体,所以开始之前,我们首先用 nyholm/psr7-server
来生成这个 ServerRequest
.
use Nyholm\Psr7\Factory\Psr17Factory;
use Nyholm\Psr7Server\ServerRequestCreator;
use Psr\Http\Message\ServerRequestInterface;
$psr17Factory = new Psr17Factory();
$creator = new ServerRequestCreator(
$psr17Factory,
$psr17Factory,
$psr17Factory,
$psr17Factory
);
/** @var ServerRequestInterface $request */
$request = $creator->fromGlobals();
OK, 准备工作结束,进入正题!我们的目标很简单,实现一个在网络上流传已久的“价值百万的人工智能程序”。
这是一个对话程序,它可以智能的回答用户的任何提问,显然,这个应用只需要一个单一的接口,所以我们选择 Handler
作为处理器
来承载这段逻辑。Handler
我们向 Handler 传入一个 callable
对象作为逻辑的主体,Handler 会将过滤后的 ServerRequestInterface
实例传递给 callable
对象作为参数。
use ConstanzeStandard\Fluff\Application;
use ConstanzeStandard\Fluff\RequestHandler\Handler;
use Psr\Http\Message\ServerRequestInterface;
use Nyholm\Psr7\Response;
$handler = new Handler(function(ServerRequestInterface $request) {
$queryParams = $request->getQueryParams();
$words = $queryParams['words'];
$words = str_replace(
['吗', '?', '?'],
['', '!', '!'],
$words
);
return new Response(200, ['Content-Type' => 'text/plain'], $words);
});
现在,主要逻辑已经完成,我们需要把这个处理器
$handler
传入入口模块,然后调用 handle
方法,载入事先准备好的 ServerRequest
对象,触发处理链条。
$app = new Application($handler);
$app->handle($rquest);
看似大功告成了,现在访问 http://127.0.0.1:8080?words=在吗?
哇哦,什么都没有。因为我们犯了一个错误,我们只是完成了逻辑执行,但是并没有输出 Response
. 看到这里你也许会很奇怪,因为这和以往使用的框架不同,FLuff 绝不会做多余的事情。要想输出应答,我们就需要找到作用于输出缓冲区(Output Buffer)
的中间件 EndOutputBuffer
, 将这个中间件添加到 Application
中。让我们来重构这段代码:
use ConstanzeStandard\Fluff\Middleware\EndOutputBuffer;
...
$app = new Application($handler);
$app->addMiddleware(new EndOutputBuffer());
$app->handle($request);
EndOutputBuffer
的职责是关闭缓冲区,并且会冲刷掉带有 flushable
标志的输出缓冲区,或清空带有 cleanable
标志的输出缓冲区,最终将所有缓冲区关闭。输出内容的大小,默认每 4096
字节会做一次 flush 操作,你也可以通过构造方法的参数改变这个值的大小。
现在,我们再来访问一次 http://127.0.0.1:8080?words=在吗?
在!
编写中间件
上面的例子中有一个不合理的地方,就是如果我们没有传入 words
参数,程序就会崩溃,你可以选择在处理器内部加一套验证的逻辑,但这样会让代码变得臃肿不堪,另一方面,请求处理器也不期望得到一个不符合要求 Request
.
一个好的做法是,加一个验证 GET 请求参数的中间件(Middleware)
。Fluff 的中间件系统符合 PSR-15
的标准,你的中间件也必须实现 \Psr\Http\Server\MiddlewareInterface
接口。
下面,我们来实现这个验证请求的中间件,如果请求没有传递 words
参数,则直接返回 400 Bad Request
响应体。
use Nyholm\Psr7\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class VerificationMiddleware implements MiddlewareInterface
{
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$queryParams = $request->getQueryParams();
if (array_key_exists('words', $queryParams)) {
return $handler->handle($request);
}
return new Response(400);
}
}
这个中间件应该放在 EndOutputBuffer
的里层,因为 VerificationMiddleware
需要通过下一层的 EndOutputBuffer
输出响应。在代码中,应该在 EndOutputBuffer
之前添加。
$app = new Application($requestHandler);
$app->addMiddleware(new VerificationMiddleware());
$app->addMiddleware(new EndOutputBuffer());
$app->handle($rquest);
我们再来做一下测试,访问 http://127.0.0.1:8080
是不是出现了 400 Bad Request
的响应呢 :)
到现在,这个最小化应用已经完成了。对于使用者来说,选择哪种处理器(Handler)
将决定后续的开发模式,甚至影响代码的风格。而功能的扩展,则完全取决于使用了哪些中间件(Middleware)
。
Fluff 提供了多种多样的处理器和中间件,可以完成风格迥异的架构,这些我们将在后续的章节中学到。