ThinkSSL🔒 一键申购 5分钟快速签发 30天无理由退款 购买更放心 广告
# 5.4 请求上下文 我们实现了纯异步长驻的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); ``` 响应结果如: ```json [ '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'); ``` ### 日志对象 日志对象提供框架的日志功能,是满足pr-4的标准日志对象,如下示例: ``` $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() ```