Files
zhamao-framework/src/ZM/Event/SwooleEvent/OnRequest.php
sunxyw 3bbe21268b add auto response serialize for http request (#104)
* add auto response serialize for http request

* fix possible duplicate response end
2022-04-29 15:36:48 +08:00

154 lines
5.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace ZM\Event\SwooleEvent;
use Error;
use Exception;
use Swoole\Coroutine;
use Swoole\Http\Request;
use ZM\Annotation\Http\RequestMapping;
use ZM\Annotation\Swoole\OnRequestEvent;
use ZM\Annotation\Swoole\OnSwooleEvent;
use ZM\Annotation\Swoole\SwooleHandler;
use ZM\Config\ZMConfig;
use ZM\Console\Console;
use ZM\Container\Container;
use ZM\Context\Context;
use ZM\Context\ContextInterface;
use ZM\Event\EventDispatcher;
use ZM\Event\SwooleEvent;
use ZM\Exception\InterruptException;
use ZM\Http\Response;
use ZM\Utils\HttpUtil;
/**
* Class OnRequest
* @SwooleHandler("request")
*/
class OnRequest implements SwooleEvent
{
public function onCall(?Request $request, ?\Swoole\Http\Response $response)
{
$response = new Response($response);
foreach (ZMConfig::get('global')['http_header'] as $k => $v) {
$response->setHeader($k, $v);
}
unset(Context::$context[Coroutine::getCid()]);
Console::debug('Calling Swoole "request" event from fd=' . $request->fd);
set_coroutine_params(['request' => $request, 'response' => $response]);
$this->registerRequestContainerBindings($request, $response);
$dis1 = new EventDispatcher(OnRequestEvent::class);
$dis1->setRuleFunction(function ($v) {
return (bool) eval('return ' . $v->getRule() . ';');
});
$dis = new EventDispatcher(OnSwooleEvent::class);
$dis->setRuleFunction(function ($v) {
if ($v->getRule() == '') {
return strtolower($v->type) == 'request';
}
if (strtolower($v->type) == 'request' && eval('return ' . $v->getRule() . ';')) {
return true;
}
return false;
});
try {
$dis1->dispatchEvents($request, $response);
$dis->dispatchEvents($request, $response);
if ($dis->status === EventDispatcher::STATUS_NORMAL && $dis1->status === EventDispatcher::STATUS_NORMAL) {
$result = HttpUtil::parseUri($request, $response, $request->server['request_uri'], $node, $params);
if ($result === true) {
ctx()->setCache('params', $params);
$dispatcher = new EventDispatcher(RequestMapping::class);
$div = new RequestMapping($node['route']);
$div->params = $params;
$div->method = $node['method'];
$div->request_method = $node['request_method'];
$div->class = $node['class'];
$dispatcher->dispatchEvent($div, null, $params, $request, $response);
if (!$response->isEnd()) {
$this->response($response, $dispatcher->store);
}
}
}
if (!$response->isEnd()) {
HttpUtil::responseCodePage($response, 404);
}
} catch (InterruptException $e) {
// do nothing
} catch (Exception $e) {
$response->status(500);
Console::info(
$request->server['remote_addr'] . ':' . $request->server['remote_port'] .
' [' . $response->getStatusCode() . '] ' . $request->server['request_uri']
);
if (!$response->isEnd()) {
if (ZMConfig::get('global', 'debug_mode')) {
$response->end(zm_internal_errcode('E00023') . 'Internal server exception: ' . $e->getMessage());
} else {
$response->end(zm_internal_errcode('E00023') . 'Internal server error.');
}
}
Console::error(zm_internal_errcode('E00023') . 'Internal server exception (500), caused by ' . get_class($e) . ': ' . $e->getMessage());
Console::log($e->getTraceAsString(), 'gray');
} catch (Error $e) {
$response->status(500);
Console::info(
$request->server['remote_addr'] . ':' . $request->server['remote_port'] .
' [' . $response->getStatusCode() . '] ' . $request->server['request_uri']
);
if (!$response->isEnd()) {
$error_msg = $e->getMessage() . ' at ' . $e->getFile() . '(' . $e->getLine() . ')';
if (ZMConfig::get('global', 'debug_mode')) {
$response->end(zm_internal_errcode('E00023') . 'Internal server error: ' . $error_msg);
} else {
$response->end(zm_internal_errcode('E00023') . 'Internal server error.');
}
}
Console::error(zm_internal_errcode('E00023') . 'Internal server error (500), caused by ' . get_class($e) . ': ' . $e->getMessage());
Console::log($e->getTraceAsString(), 'gray');
} finally {
container()->flush();
}
}
/**
* 注册请求容器绑定
*/
private function registerRequestContainerBindings(Request $request, Response $response): void
{
$container = Container::getInstance();
// $container->setLogPrefix("[Container#{$frame->fd}]");
$container->instance(Request::class, $request);
$container->bind(ContextInterface::class, function () {
return ctx();
});
$container->alias(ContextInterface::class, Context::class);
}
/**
* 返回响应
* @param mixed $result
*/
private function response(Response $response, $result): void
{
if (is_string($result)) {
$response->end($result);
} else {
try {
$response->header('Content-Type', 'application/json');
$response->end(json_encode($result, JSON_UNESCAPED_UNICODE));
} catch (Exception $e) {
Console::error('无法将响应转换为JSON' . $e->getMessage());
$response->end(json_encode(zm_internal_errcode('E00023') . 'Internal server error.'));
}
}
}
}