Http.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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 string
  41. */
  42. protected $routePath;
  43. /**
  44. * 是否绑定应用
  45. * @var bool
  46. */
  47. protected $isBind = false;
  48. public function __construct(App $app)
  49. {
  50. $this->app = $app;
  51. $this->routePath = $this->app->getRootPath() . 'route' . DIRECTORY_SEPARATOR;
  52. }
  53. /**
  54. * 设置应用名称
  55. * @access public
  56. * @param string $name 应用名称
  57. * @return $this
  58. */
  59. public function name(string $name)
  60. {
  61. $this->name = $name;
  62. return $this;
  63. }
  64. /**
  65. * 获取应用名称
  66. * @access public
  67. * @return string
  68. */
  69. public function getName(): string
  70. {
  71. return $this->name ?: '';
  72. }
  73. /**
  74. * 设置应用目录
  75. * @access public
  76. * @param string $path 应用目录
  77. * @return $this
  78. */
  79. public function path(string $path)
  80. {
  81. if (substr($path, -1) != DIRECTORY_SEPARATOR) {
  82. $path .= DIRECTORY_SEPARATOR;
  83. }
  84. $this->path = $path;
  85. return $this;
  86. }
  87. /**
  88. * 获取应用路径
  89. * @access public
  90. * @return string
  91. */
  92. public function getPath(): string
  93. {
  94. return $this->path ?: '';
  95. }
  96. /**
  97. * 获取路由目录
  98. * @access public
  99. * @return string
  100. */
  101. public function getRoutePath(): string
  102. {
  103. return $this->routePath;
  104. }
  105. /**
  106. * 设置路由目录
  107. * @access public
  108. * @param string $path 路由定义目录
  109. */
  110. public function setRoutePath(string $path): void
  111. {
  112. $this->routePath = $path;
  113. }
  114. /**
  115. * 设置应用绑定
  116. * @access public
  117. * @param bool $bind 是否绑定
  118. * @return $this
  119. */
  120. public function setBind(bool $bind = true)
  121. {
  122. $this->isBind = $bind;
  123. return $this;
  124. }
  125. /**
  126. * 是否绑定应用
  127. * @access public
  128. * @return bool
  129. */
  130. public function isBind(): bool
  131. {
  132. return $this->isBind;
  133. }
  134. /**
  135. * 执行应用程序
  136. * @access public
  137. * @param Request|null $request
  138. * @return Response
  139. */
  140. public function run(Request $request = null): Response
  141. {
  142. //初始化
  143. $this->initialize();
  144. //自动创建request对象
  145. $request = $request ?? $this->app->make('request', [], true);
  146. $request->filter(['htmlspecialchars']);
  147. $this->app->instance('request', $request);
  148. try {
  149. $response = $this->runWithRequest($request);
  150. } catch (Throwable $e) {
  151. $this->reportException($e);
  152. $response = $this->renderException($request, $e);
  153. }
  154. return $response;
  155. }
  156. /**
  157. * 初始化
  158. */
  159. protected function initialize()
  160. {
  161. if (!$this->app->initialized()) {
  162. $this->app->initialize();
  163. }
  164. }
  165. /**
  166. * 执行应用程序
  167. * @param Request $request
  168. * @return mixed
  169. */
  170. protected function runWithRequest(Request $request)
  171. {
  172. // 加载全局中间件
  173. $this->loadMiddleware();
  174. // 监听HttpRun
  175. $this->app->event->trigger(HttpRun::class);
  176. return $this->app->middleware->pipeline()
  177. ->send($request)
  178. ->then(function ($request) {
  179. return $this->dispatchToRoute($request);
  180. });
  181. }
  182. protected function dispatchToRoute($request)
  183. {
  184. $withRoute = $this->app->config->get('app.with_route', true) ? function () {
  185. $this->loadRoutes();
  186. } : null;
  187. return $this->app->route->dispatch($request, $withRoute);
  188. }
  189. /**
  190. * 加载全局中间件
  191. */
  192. protected function loadMiddleware(): void
  193. {
  194. if (is_file($this->app->getBasePath() . 'middleware.php')) {
  195. $this->app->middleware->import(include $this->app->getBasePath() . 'middleware.php');
  196. }
  197. $appRootNamespace = $this->app->getRootNamespace();
  198. $rootPath = root_path();
  199. $vendorMiddlewareFile = "{$rootPath}vendor/thinkcmf/cmf-{$appRootNamespace}/src/middleware.php";
  200. if (is_file($vendorMiddlewareFile)) {
  201. $this->app->middleware->import(include $vendorMiddlewareFile);
  202. }
  203. }
  204. /**
  205. * 加载路由
  206. * @access protected
  207. * @return void
  208. */
  209. protected function loadRoutes(): void
  210. {
  211. $appRootNamespace = $this->app->getRootNamespace();
  212. $rootPath = root_path();
  213. if ($appRootNamespace == 'app') {
  214. $routePath = "{$rootPath}data/route/";
  215. if (is_dir($routePath)) {
  216. $files = glob($routePath . '*.php');
  217. foreach ($files as $file) {
  218. include $file;
  219. }
  220. }
  221. // 加载路由定义
  222. $routePath = $this->getRoutePath();
  223. if (is_dir($routePath)) {
  224. $files = glob($routePath . '*.php');
  225. foreach ($files as $file) {
  226. include $file;
  227. }
  228. }
  229. }
  230. if ($appRootNamespace == 'api') {
  231. $routeFile = "{$rootPath}vendor/thinkcmf/cmf-api/src/route.php";
  232. if (is_file($routeFile)) {
  233. include_once $routeFile;
  234. }
  235. }
  236. $this->app->event->trigger(RouteLoaded::class);
  237. }
  238. /**
  239. * Report the exception to the exception handler.
  240. *
  241. * @param Throwable $e
  242. * @return void
  243. */
  244. protected function reportException(Throwable $e)
  245. {
  246. $this->app->make(Handle::class)->report($e);
  247. }
  248. /**
  249. * Render the exception to a response.
  250. *
  251. * @param Request $request
  252. * @param Throwable $e
  253. * @return Response
  254. */
  255. protected function renderException($request, Throwable $e)
  256. {
  257. return $this->app->make(Handle::class)->render($request, $e);
  258. }
  259. /**
  260. * HttpEnd
  261. * @param Response $response
  262. * @return void
  263. */
  264. public function end(Response $response): void
  265. {
  266. $this->app->event->trigger(HttpEnd::class, $response);
  267. //执行中间件
  268. $this->app->middleware->end($response);
  269. // 写入日志
  270. $this->app->log->save();
  271. }
  272. }