Http.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types = 1);
  12. namespace think;
  13. use think\event\HttpEnd;
  14. use think\event\HttpRun;
  15. use think\event\RouteLoaded;
  16. use think\exception\Handle;
  17. use Throwable;
  18. /**
  19. * Web应用管理类
  20. * @package think
  21. */
  22. class Http
  23. {
  24. /**
  25. * @var App
  26. */
  27. protected $app;
  28. /**
  29. * 应用名称
  30. * @var string
  31. */
  32. protected $name;
  33. /**
  34. * 应用路径
  35. * @var string
  36. */
  37. protected $path;
  38. /**
  39. * 是否绑定应用
  40. * @var bool
  41. */
  42. protected $isBind = false;
  43. public function __construct(App $app)
  44. {
  45. $this->app = $app;
  46. $this->routePath = $this->app->getRootPath() . 'route' . DIRECTORY_SEPARATOR;
  47. }
  48. /**
  49. * 设置应用名称
  50. * @access public
  51. * @param string $name 应用名称
  52. * @return $this
  53. */
  54. public function name(string $name)
  55. {
  56. $this->name = $name;
  57. return $this;
  58. }
  59. /**
  60. * 获取应用名称
  61. * @access public
  62. * @return string
  63. */
  64. public function getName(): string
  65. {
  66. return $this->name ?: '';
  67. }
  68. /**
  69. * 设置应用目录
  70. * @access public
  71. * @param string $path 应用目录
  72. * @return $this
  73. */
  74. public function path(string $path)
  75. {
  76. if (substr($path, -1) != DIRECTORY_SEPARATOR) {
  77. $path .= DIRECTORY_SEPARATOR;
  78. }
  79. $this->path = $path;
  80. return $this;
  81. }
  82. /**
  83. * 获取应用路径
  84. * @access public
  85. * @return string
  86. */
  87. public function getPath(): string
  88. {
  89. return $this->path ?: '';
  90. }
  91. /**
  92. * 获取路由目录
  93. * @access public
  94. * @return string
  95. */
  96. public function getRoutePath(): string
  97. {
  98. return $this->routePath;
  99. }
  100. /**
  101. * 设置路由目录
  102. * @access public
  103. * @param string $path 路由定义目录
  104. * @return string
  105. */
  106. public function setRoutePath(string $path): void
  107. {
  108. $this->routePath = $path;
  109. }
  110. /**
  111. * 设置应用绑定
  112. * @access public
  113. * @param bool $bind 是否绑定
  114. * @return $this
  115. */
  116. public function setBind(bool $bind = true)
  117. {
  118. $this->isBind = $bind;
  119. return $this;
  120. }
  121. /**
  122. * 是否绑定应用
  123. * @access public
  124. * @return bool
  125. */
  126. public function isBind(): bool
  127. {
  128. return $this->isBind;
  129. }
  130. /**
  131. * 执行应用程序
  132. * @access public
  133. * @param Request|null $request
  134. * @return Response
  135. */
  136. public function run(Request $request = null): Response
  137. {
  138. //自动创建request对象
  139. $request = $request ?? $this->app->make('request', [], true);
  140. $this->app->instance('request', $request);
  141. try {
  142. $response = $this->runWithRequest($request);
  143. } catch (Throwable $e) {
  144. $this->reportException($e);
  145. $response = $this->renderException($request, $e);
  146. }
  147. return $response;
  148. }
  149. /**
  150. * 初始化
  151. */
  152. protected function initialize()
  153. {
  154. if (!$this->app->initialized()) {
  155. $this->app->initialize();
  156. }
  157. }
  158. /**
  159. * 执行应用程序
  160. * @param Request $request
  161. * @return mixed
  162. */
  163. protected function runWithRequest(Request $request)
  164. {
  165. $this->initialize();
  166. // 加载全局中间件
  167. $this->loadMiddleware();
  168. // 设置开启事件机制
  169. $this->app->event->withEvent($this->app->config->get('app.with_event', true));
  170. // 监听HttpRun
  171. $this->app->event->trigger(HttpRun::class);
  172. return $this->app->middleware->pipeline()
  173. ->send($request)
  174. ->then(function ($request) {
  175. return $this->dispatchToRoute($request);
  176. });
  177. }
  178. protected function dispatchToRoute($request)
  179. {
  180. $withRoute = $this->app->config->get('app.with_route', true) ? function () {
  181. $this->loadRoutes();
  182. } : null;
  183. return $this->app->route->dispatch($request, $withRoute);
  184. }
  185. /**
  186. * 加载全局中间件
  187. */
  188. protected function loadMiddleware(): void
  189. {
  190. if (is_file($this->app->getBasePath() . 'middleware.php')) {
  191. $this->app->middleware->import(include $this->app->getBasePath() . 'middleware.php');
  192. }
  193. }
  194. /**
  195. * 加载路由
  196. * @access protected
  197. * @return void
  198. */
  199. protected function loadRoutes(): void
  200. {
  201. // 加载路由定义
  202. $routePath = $this->getRoutePath();
  203. if (is_dir($routePath)) {
  204. $files = glob($routePath . '*.php');
  205. foreach ($files as $file) {
  206. include $file;
  207. }
  208. }
  209. $this->app->event->trigger(RouteLoaded::class);
  210. }
  211. /**
  212. * Report the exception to the exception handler.
  213. *
  214. * @param Throwable $e
  215. * @return void
  216. */
  217. protected function reportException(Throwable $e)
  218. {
  219. $this->app->make(Handle::class)->report($e);
  220. }
  221. /**
  222. * Render the exception to a response.
  223. *
  224. * @param Request $request
  225. * @param Throwable $e
  226. * @return Response
  227. */
  228. protected function renderException($request, Throwable $e)
  229. {
  230. return $this->app->make(Handle::class)->render($request, $e);
  231. }
  232. /**
  233. * HttpEnd
  234. * @param Response $response
  235. * @return void
  236. */
  237. public function end(Response $response): void
  238. {
  239. $this->app->event->trigger(HttpEnd::class, $response);
  240. //执行中间件
  241. $this->app->middleware->end($response);
  242. // 写入日志
  243. $this->app->log->save();
  244. }
  245. }