我们实现了纯异步长驻的PHP Http Server,内存中的对象和数据均会复用,所以PHP的全局变量$_GET/$_POST/$_GLOBAL/$_REQUEST/类的静态属性要慎用,最好是不用。因为同一个Worker进程在同一时间有可能正在处理多个请求,比如A请求修改了全局的数据很有可能会影响B请求的正确处理。
那在处理请求过程中,如何能够让程序控制流向下传递数据,如何在同一个请求中共享和当前请求相关的数据呢,如何在任何地方方便的获取当前请求相关的数据?这就是请求上下文解决的问题。
在框架中封装了请求的上下文,在任何时候,有访问请求对象、响应输出对象、日志、日志ID、对象池操作、自定义请求数据的需要,都必须通过请求上下文对象来完成。
通常情况下,在MSF框架内直接使用$this->getContext()即可,包括在Controller,Model,Task。
需要特别注意的是,第三方或者自定义lib,通过对象池创建的对象是直接注入context属性,也是通过$this->getContext()的方法获取请求上下文对象。
提供了获取get/post/header/cookie/server等数据,通过请求上下文来获取,即$this->getContext()->getInput(),如下示例:
在控制器中使用示例:
// 指定获取 get 参数
$this->getContext()->getInput()->get('uid');
// 指定获取 post 参数
$this->getContext()->getInput()->post('uid');
// 指定获取 get & post 参数
$this->getContext()->getInput()->getPost('uid'); // 优先从 get 中取
$this->getContext()->getInput()->postGet('uid'); // 优先从 post 中去
// 获取所有 get & post 参数
$this->getContext()->getInput()->getAllPostGet();
// 获取 header 头信息
$this->getContext()->getInput()->getHeader('x-ngx-id');
// 获取所有 header 头信息
$this->getContext()->getInput()->getAllHeader();
// 获取所有 server 信息
$this->getContext()->getInput()->getAllServer();
// 获取原始的 post 包体
$this->getContext()->getInput()->getRawContent();
// 获取 cookie 参数
$this->getContext()->getInput()->getCookie('uid');
// 获取用户 ip
$this->getContext()->getInput()->getRemoteAddr();
// 获取 pathinfo 信息
$this->getContext()->getInput()->getPathInfo();
// 获取请求 uri
$this->getContext()->getInput()->getRequestUri();
提供了设置常用的header(如:content-type/cookie)等方法,响应json、html等数据格式
在控制器中调用:
// 响应数据
$this->getContext()->getOutput()->output($data, $status = 200);
响应结果如:
581af00d4b58d59d22e8d7a6
// 输出json数据格式
$this->getContext()->getOutput()->outputJson($data, $status = 200);
响应结果如:
[
"581af00d4b58d59d22e8d7a6",
"581af00d4b58d59d22e8d7a7",
"581af00d4b58d59d22e8d7a8",
]
$status
为HTTP状态码,默认为200。
// 输出html数据(自动加载并渲染模板)
$this->getContext()->getOutput()->outputView($data);
但是在控制器基类中已经直接封装了三个同名的方法Controller::output($data, $status = 200)
, Controller::outputJson($data, $status = 200)
,Controller::outputView($data, $view = null)
,可以直接使用。
// 设置Content-Type报头
$this->getContext()->getOutput()->setContentType('text/html; charset=UTF-8');
// 直接设置任何其他报头
$this->getContext()->getOutput()->setHeader('ContentType: text/html; charset=UTF-8');
另外,需要特别注意的是Http Server响应请求,实际上是调用了$this->getContext()->getOutput()->end()
方法,所以如果仅仅是输出响应也可以直接调用:
// 直接响应http请求,不经过任何的加工
$this->getContext()->getOutput()->end('ok');
日志对象提供框架的日志功能,是满足psr-3的标准日志对象,如下示例:
$this->getContext()->getLog()->error('致命错误')
$this->getContext()->getLog()->warning('警告错误')
$this->getContext()->getLog()->info('info日志')
$this->getContext()->getLog()->pushLog('key', $value)
对象池,任何有创建类对象的需求,均要使用对象池的方式,更多的介绍会在对象池
,如下示例:
$this->getContext()->getObjectPool()->get(ClassName)
通常情况下,框架内置的类均use MI;
,则可以直接使用$this->getObject($className, ['构造参数列表'])
来创建对象,第三方lib也可使用trait来扩展类的功能。
用户自定义的请求上下文数据应用场景比如,多个地方均需要验证用户的登录信息,验证成功就可以将用户了uid/name/email等信息设置到请求的上下文,然后任何其他代码需要访问用户信息就可以直接使用。另外需要注意的是尽可能设置为标题和数组的自定义数据,减少内存泄露的风险。
// 设置自定义key对应的value
$this->getContext()->setUserDefined('key', 'value')
// 获取自定义的key对应的value
$this->getContext()->getUserDefined('key')
// 获取当前请求的控制器名
$this->getContext()->getControllerName()
// 获取当前请求的控制器方法名
$this->getContext()->getActionName()
- 目录
- 上一节: 异步HttpClient
- 下一节: 连接池