下载好ThinkPHP5.0
后,在根目录下创建server
目录,用于存放swoole
的服务等.
创建Http服务
mkdir server
cd server
touch http_server.php
直接引用之前Http
的代码吧.
$server = new Swoole\Http\Server("0.0.0.0",9503);
// 设置静态资源目录
/*
* enable_static_handel开启静态文件请求处理功能,需配合document_root使用.
* document_root配置静态文件根目录,与enable_static_handler配合使用。
* 注意:设置了set后将不会走on方法
* */
$server->set([
'enable_static_handler' => true,
'document_root' => "/data/wwwroot/test"
]);
/*
* end向客户端浏览器发送HTML内容,只能调用一次.
* 如果需要分多次向客户端发送数据,请使用write方法
* */
$server->on('request', function($request,$response) {
$response->end("<h1>hello</h1>");
});
$server->start();
现在我们假如我们要在浏览器通过live.dev:9503/index/index/qvbilam
来访问的时候.如果我们不去做修改是根本找不到tp
框架下index/index/qvbilam
的内容的.
当我们去请求地址的时候肯定是走到代码中request
的回调里面. 我们需要在回调函数里处理相应的逻辑.
当我们访问thinkphp
肯定是会先访问一个入口文件的,即pubilic/index.php
.所以每次访问都时候都必须让他经过index.php
.就好了~
在swoole
中有个onworkstart
函数,如何理解onworkerstart
函数.
现在服务设置中设置worker_num
.当我们启动这个服务的时候呢.它会走到workerstart
一个事件回调里面去,所以在启动服务的时候应该把thinkphp
框架里面的一些内容加载到worker
进程里去.
首先看一下thinkphp5.0
的index.php
// [ 应用入口文件 ]
// 定义应用目录
define('APP_PATH', __DIR__ . '/../application/');
// 加载框架引导文件
require __DIR__ . '/../thinkphp/start.php';
可以看到它又加载了start.php
的引导文件,查看start.php
.
namespace think;
// ThinkPHP 引导文件
// 1. 加载基础文件
require __DIR__ . '/base.php';
// 2. 执行应用
App::run()->send();
start.php
文件加载了一个base.php
的核心文件,所以直接把base.php
加载到workerstart
里面去.这样是为了能应用热加载./server/http_server.php
的WorkerStart
如下
$server->on('WorkerStart', function (swoole_server $server, $worker_id) {
// 定义应用目录 index.php
define('APP_PATH', __DIR__ . '/../application/');
// 再去加载php的引导文件
// 不直接复制index.php的文件中的引入start.php.
// 是因为在start.php中还有执行应用我们不需要,所以直接引入base.php就行
// x加载基础文件
require __DIR__ . '/../thinkphp/base.php';
});
start.php
文件中的执行应用是应该放在request
的回调里面去,就是这行代码
// 2. 执行应用
App::run()->send();
# 添加到/server/http_server.php的request方法中
$server->on('request', function ($request, $response) use ($server) {
// 这里一定要加上think命名空间,否则报错
think\App::run()->send();
$response->end("<h1>hello</h1>");
}
直接启动,出现报错
Warning: require(/Users/qvbi lam/Sites/liveTelecastsereras php): failed to open stream: No such file or directory in /Users/qvbi Lam/Sites/liveTelecast/server/http_server.php on line 16
PHP Fatal error: require(): Failed opening required in /Users/qvbi lam/Sites/liveTelecastserver/base php' (include_path=' .:/usr/local/Cellar/php/7.3.1/ share/php/pear') in /Users/qvbi lam/Sites/liveTelecast/server/http_server.php on line 16
Fatal error: require(): Failed opening required ' /Users/qvbi Lam/Sites/liveTelecast/server/base.php' (include_path='. :/usr/local/Cellar/pho/7.3.1/share/pho/pear') in /Users/qvbi lam/Sites/liveTelecast/server/http_server.php on line 16
别担心哈.这是提示找不到文件.因为从/public/index.php
文件复制的内容.所以__DIR__
指的路径就是/public
.而服务是在/server
,修改/server/http_server.php
.
$server->on('WorkerStart', function (swoole_server $server, $worker_id) {
// 定义应用目录 index.php
define('APP_PATH', __DIR__ . '/../application/');
// 再去加载php的引导文件
// 不直接复制index.php的文件中的引入start.php.
// 是因为在start.php中还有执行应用我们不需要.
// 所以直接引入base.php就行
// x加载基础文件
require __DIR__ . '/../thinkphp/base.php';
});
这样就没有错误啦~http
服务启动
关于引用
有些人也可能会想为什么不直接引用start.php
呢?那来试试引用start.php
会发生什么.
修改application\index\controller\Index.php
public function index()
{
return 'Index' . PHP_EOL;
}
将/server/http_server.php
中WorkerStart
包含的base.php
替换成start.php
后,启动服务
php server/http_server.php
# 输出
Index
Index
Index
Index
Index
诶嘿~输出了五次index/index/index()
返回内容.因为当启动http
服务的时候首先在设置中设置了5个worker
进程.会启动五次workerStart
.而workerStart
包含了start.php
.执行了thinkphp
的应用
// 2. 执行应用
App::run()->send();
这个内容就会去执行框架里的内容.因为没有传控制器模型方法,会自动默认为index/index/index
.所以没必要执行这个,只需要包涵框架里的文件加载到worker
里面就行,真正执行的只要在用户请求的时候再执行,也就是说将执行应用放到 request
里面就行.
检测服务
返回内容
当我们通过浏览器访问http
服务的时候页面返回的是hello
.而我们的index/index/index()
返回的是Index
啊!其实是因为server/http_server.php
中的request
中的这行代码
# 向浏览器输出并结束
$response->end("<h1>hello</h1>");
# 修改成
// 执行应用
ob_start();
try {
think\App::run()->send();
} catch (\Exception $e) {
// 可以输出一些错误。打错误日志什么的。根据自己业务吧
}
$rst = ob_get_contents();
ob_end_clean();
$response->end($rst);
重启服务发现返回的是index/index/index()
返回的内容
获取传参
修改index/index/index()
public function index()
{
dump($_GET);
return 'hello 我是qvbilam_index' . PHP_EOL;
}
访问测试
# 请求 get['gy'] = 1
http://live.dev:9503/index/index/index?gy=1
# 返回结果 get['gy'] = 1
array(1){
["gy"]=>string(1)"1"
}hello 我是qvbilam_index
# 请求 get['sb'] = 'zcx'
http://live.dev:9503/index/index/index?sb=zcx
# 返回 get['gy'] = 1 get['sb'] = 'zcx'
array(2){
["gy"]=>string(1)"1"
["sb"=>string(3)"zcx"]
}hello 我是qvbilam_index
这是因为swoole
对超全局变量get
,post
,globals
等,如果进程还在,它是不会释放的.这样就就很难受,我们可以对这些参数进行判断,如果存在就删除它.
在server/http_server
的request
添加超全局变量处理逻辑.
$server->on('request', function ($request, $response) use ($server) {
if (isset($request->server)) {
foreach ($request->server as $key => $val) {
$_SERVER[strtoupper($key)] = $val;
}
}
if (isset($request->header)) {
foreach ($request->header as $key => $val) {
$_SERVER[strtoupper($key)] = $val;
}
}
$_GET = [];
if (isset($request->get)) {
foreach ($request->get as $key => $val) {
$_GET[$key] = $val;
}
}
$_POST = [];
if (isset($request->post)) {
foreach ($request->post as $key => $val) {
$_POST[$key] = $val;
}
}
// 执行应用
ob_start();
try {
think\App::run()->send();
} catch (\Exception $e) {
// 可以输出一些错误。打错误日志什么的。根据自己业务吧
}
$rst = ob_get_contents();
ob_end_clean();
$response->end($rst);
});
重启测试,获取传参没有问题啦~
路由访问
创建新方法index/index/index.php
public function qvbilam()
{
echo 'qvbilam';
}
重启访问
http://live.dev:9503/index/index/qvbilam
# 返回的结果是index/index/index的内容
hello 我是qvbilam_index
# 打印$_server,再次访问返回
Array
(
[request_method] => GET
[request_uri] => /index/index/qvbilam
[path_info] => /index/index/qvbilam
...
)
# swoole是没有问题的
查看thinkphp
的请求.用它的内置方法
echo request()->action();
$response->end($rst);
# 重启访问,终端返回结果
index
是因为tp
会把控制器方法放到一个变量里去,而swoole
是不会注销掉的.所以会一直访问之前的action
.所以问题可能在server\http_server.php
的request
中.
# 猜测问题所在
think\App::run()->send();
进入/thinkphp/library/think/App.php
中查看run()
...
// 未设置调度信息则进行 URL 路由检测
if (empty($dispatch)) {
$dispatch = self::routeCheck($request, $config);
}
...
查看routeCheck()
public static function routeCheck($request, array $config)
{
$path = $request->path();
...
}
继续查看path()
,进入/thinkphp/library/think/Request.php
public function path()
{
if (is_null($this->path)) {
$suffix = Config::get('url_html_suffix');
$pathinfo = $this->pathinfo();
if (false === $suffix) {
// 禁止伪静态访问
$this->path = $pathinfo;
} elseif ($suffix) {
// 去除正常的URL后缀
$this->path = preg_replace('/\.(' . ltrim($suffix, '.') . ')$/i', '', $pathinfo);
} else {
// 允许任何后缀访问
$this->path = preg_replace('/\.' . $this->ext() . '$/i', '', $pathinfo);
}
}
return $this->path;
}
如果路由第一次来会把他储存起,再进来因为没有释放内存就把第一次的请求返回.所以让每次请求都重新设置path
.把if (is_null($this->path))
的判断去掉.这里面还有个pathinfo()
方法也是一样的。把if (is_null($this->pathinfo))
判断去掉.
再在pathinfo()
添加
public function pathinfo()
{
if (isset($_SERVER['PATH_INFO']) && $_SERVER['PATH_INFO'] != '/') {
return ltrim($_SERVER['PATH_INFO'], '/');
}
// if (is_null($this->pathinfo)) {
...
}
重启访问测试,没有问题~
面向对象优化
在server
目录下新建http.php
对swoole的http
服务进行面向对象编程.废话不多说,直接复制粘贴~
very good
6666
6666666
666666
马化腾