LaravelS
- 基于 Swoole
加速 Laravel
/Lumen
LaravelS
是一个胶水项目,用于快速集成Swoole
到Laravel
或Lumen
,然后赋予它们更好的性能、更多可能性。Githubhttps://learnku.com/articles/8050/laravels-accelerate-laravellumen-based-on-swoole-take-you-fly
特性
内置Http
/WebSocket
服务器
多端口混合协议
协程
自定义进程
常驻内存
异步的事件监听
异步的任务队列
毫秒级定时任务
平滑Reload
修改代码后自动Reload
同时支持Laravel
/Lumen
,兼容主流版本
简单,开箱即用
要求
依赖
说明
PHP
>=5.5.9
推荐PHP7+
Swoole
>=1.7.19
从2.0.12开始不再支持PHP5
推荐4.2.3+
Laravel/Lumen
>= 5.1
推荐5.6+
安装
通过Composer安装(packagist)
1 composer require "hhxsv5/laravel-s:~3.3" -vvv
注册Service Provider(以下两步二选一)。
Laravel
: 修改文件config
/app.php
,Laravel 5.5+支持包自动发现,你应该跳过这步
1 2 3 4 'providers' => [ Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider ::class , ],
Lumen
: 修改文件bootstrap
/app.php
1 $app ->register (Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider ::class );
发布配置和二进制文件
每次升级LaravelS后,需重新发布
1 2 3 php artisan laravels publish
使用Lumen时的特别说明 : 你不需要手动加载配置laravels.php
,LaravelS
底层已自动加载。
1 2 $app ->configure ('laravels' );
修改配置config
/laravels.php
:监听的IP、端口等,请参考配置项。
运行 1 php bin/laravels {start|stop|restart|reload|info|help}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 [root@caoxl laravels] _ _ _____ | | | |/ ____| | | __ _ _ __ __ ___ _____| | (___ | | / _` | '__/ _` \ \ / / _ \ |\___ \ | |___| (_| | | | (_| |\ V / __/ |____) | |______\__,_|_| \__,_| \_/ \___|_|_____/ Speed up your Laravel/Lumen +---------------------------+---------+ | Component | Version | +---------------------------+---------+ | PHP | 7.2.7 | | Swoole | 4.2.7 | | LaravelS | 3.3.10 | | Laravel Framework [local] | 5.7.13 | +---------------------------+---------+
部署 与Nginx配合使用(推荐) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 gzip on; gzip_min_length 1024 ; gzip_comp_level 2 ; gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml application/x-httpd-php image/jpeg image/gif image/png font/ttf font/otf image/svg+xml; gzip_vary on; gzip_disable "msie6" ; upstream laravels { server 127.0 .0.1 :5200 weight=5 max_fails=3 fail_timeout=30 s; keepalive 16 ; } server { listen 80 ; server_name laravels.com; root /xxxpath/laravel-s-test/public ; access_log /yyypath/log/nginx/$server_name .access.log main; autoindex off; index index.html index.htm; location / { try_files $uri @laravels; } location @laravels { proxy_http_version 1.1 ; proxy_set_header Connection "" ; proxy_set_header X-Real-IP $remote_addr ; proxy_set_header X-Real-PORT $remote_port ; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ; proxy_set_header Host $http_host ; proxy_set_header Scheme $scheme ; proxy_set_header Server-Protocol $server_protocol ; proxy_set_header Server-Name $server_name ; proxy_set_header Server-Addr $server_addr ; proxy_set_header Server-Port $server_port ; proxy_pass http: } }
与Apache配合使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 LoadModule proxy_module /yyypath/modules/mod_deflate.so <IfModule deflate_module> SetOutputFilter DEFLATE DeflateCompressionLevel 2 AddOutputFilterByType DEFLATE text/html text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml application/x-httpd-php image/jpeg image/gif image/png font/ttf font/otf image/svg+xml </IfModule> <VirtualHost *:80 > ServerName www.laravels.com ServerAdmin hhxsv5@sina.com DocumentRoot /xxxpath/laravel-s-test/public ; DirectoryIndex index.html index.htm <Directory "/" > AllowOverride None Require all granted </Directory > LoadModule proxy_module /yyypath/modules/mod_proxy.so LoadModule proxy_module /yyypath/modules/mod_proxy_balancer.so LoadModule proxy_module /yyypath/modules/mod_lbmethod_byrequests.so.so LoadModule proxy_module /yyypath/modules/mod_proxy_http.so.so LoadModule proxy_module /yyypath/modules/mod_slotmem_shm.so LoadModule proxy_module /yyypath/modules/mod_rewrite.so ProxyRequests Off ProxyPreserveHost On <Proxy balancer: BalancerMember http: ProxySet lbmethod=byrequests </Proxy> RewriteEngine On RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f RewriteRule ^/(.*)$ balancer: ErrorLog ${APACHE_LOG_DIR}/www.laravels.com.error.log CustomLog ${APACHE_LOG_DIR}/www.laravels.com.access.log combined </VirtualHost>
启用WebSocket服务器
WebSocket服务器监听的IP和端口与Http服务器相同。
创建WebSocket Handler类,并实现接口WebSocketHandlerInterface
。start时会自动实例化,不需要手动创建示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <?php namespace App \Services ;use Hhxsv5 \LaravelS \Swoole \WebSocketHandlerInterface ;class WebSocketService implements WebSocketHandlerInterface { public function __construct ( ) { } public function onOpen (\swoole_websocket_server $server , \swoole_http_request $request ) { \Log ::info ('New WebSocket connection' , [ $request ->fd, request ()->all (), session ()->getId (), session ('xxx' ), session (['yyy' => time ()]) ]); $server ->push ($request ->fd, 'Welcome to LaravelS' ); } public function onMessage (\swoole_websocket_server $server , \swoole_websocket_frame $frame ) { \Log ::info ('Received message' , [ $frame ->fd, $frame ->data, $frame ->opcode, $frame ->finish ]); $server ->push ($frame ->fd, date ('Y-m-d H:i:s' )); } public function onClose (\swoole_websocket_server $server , $fd , $reactorId ) { } }
更改配置 config/laravels.php
1 2 3 4 5 6 7 8 9 10 11 12 'websocket' => [ 'enable' => true , 'handler' => \App\Services\WebSocketService ::class , ], 'swoole' => [ 'dispatch_mode' => 2 , ],
使用swoole_table
绑定FD
与UserId
,可选的,Swoole Table示例 也可以用其他全局存储服务,例如Redis
/Memcached
/MySQL
,但需要注意多个Swoole Server
实例时FD
可能冲突。
与Nginx配合使用(推荐)
参考 WebSocket代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 map $http_upgrade $connection_upgrade { default upgrade; '' close; } upstream laravels { server 127.0 .0.1 :5200 weight=5 max_fails=3 fail_timeout=30 s; keepalive 16 ; } server { listen 80 ; server_name laravels.com; root /xxxpath/laravel-s-test/public ; access_log /yyypath/log/nginx/$server_name .access.log main; autoindex off; index index.html index.htm; location / { try_files $uri @laravels; } location =/ws { proxy_http_version 1.1 ; proxy_set_header X-Real-IP $remote_addr ; proxy_set_header X-Real-PORT $remote_port ; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ; proxy_set_header Host $http_host ; proxy_set_header Scheme $scheme ; proxy_set_header Server-Protocol $server_protocol ; proxy_set_header Server-Name $server_name ; proxy_set_header Server-Addr $server_addr ; proxy_set_header Server-Port $server_port ; proxy_set_header Upgrade $http_upgrade ; proxy_set_header Connection $connection_upgrade ; proxy_pass http: } location @laravels { proxy_http_version 1.1 ; proxy_set_header Connection "" ; proxy_set_header X-Real-IP $remote_addr ; proxy_set_header X-Real-PORT $remote_port ; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ; proxy_set_header Host $http_host ; proxy_set_header Scheme $scheme ; proxy_set_header Server-Protocol $server_protocol ; proxy_set_header Server-Name $server_name ; proxy_set_header Server-Addr $server_addr ; proxy_set_header Server-Port $server_port ; proxy_pass http: } }
心跳配置
1 2 3 4 5 6 7 8 'swoole' => [ 'heartbeat_idle_time' => 600 , 'heartbeat_check_interval' => 60 , ],
1 2 proxy_read_timeout 60 s;
监听事件 系统事件
通常,你可以在这些事件中重置或销毁一些全局或静态的变量,也可以修改当前的请求和响应。
laravels.received_request
将 swoole_http_request
转成 Illuminate\Http\Request
后,在Laravel
内核处理请求前。
1 2 3 4 5 Event ::listen ('laravels.received_request' , function (\Illuminate\Http\Request $req , $app ) { $req ->query->set ('get_key' , 'hhxsv5' ); $req ->request->set ('post_key' , 'hhxsv5' ); });
laravels.generated_response
在Laravel
内核处理完请求后,将Illuminate\Http\Response
转成swoole_http_response
之前(下一步将响应给客户端)。
1 2 3 4 5 Event ::listen ('laravels.generated_response' , function ( \Illuminate\Http\Request $req , \Symfony\Component\HttpFoundation\Response $rsp , $app ) { $rsp ->headers->set ('header-key' , 'hhxsv5' ); });
完整如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public function boot ( ) { parent ::boot (); Event ::listen ('laravels.received_request' , function (\Illuminate\Http\Request $req , $app ) { $req ->query->set ('get_key' , 'hhxsv5' ); $req ->request->set ('post_key' , 'hhxsv5' ); }); Event ::listen ('laravels.generated_response' , function ( \Illuminate\Http\Request $req , \Symfony\Component\HttpFoundation\Response $rsp , $app ) { $rsp ->headers->set ('header-key' , 'hhxsv5' ); }); }
自定义的异步事件
此特性依赖Swoole
的AsyncTask
,必须先设置config/laravels.php
的swoole.task_worker_num
。 异步事件的处理能力受Task进程数影响,需合理设置task_worker_num 。
创建事件类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?php namespace App \Tasks ;use Hhxsv5 \LaravelS \Swoole \Task \Event ;class TestEvent extends Event { private $data ; public function __construct ($data ) { $this ->data = $data ; } public function getData ( ) { return $this ->data; } }
创建监听器类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <?php namespace App \Tasks ;use Hhxsv5 \LaravelS \Swoole \Task \Task ;use Hhxsv5 \LaravelS \Swoole \Task \Event ;use Hhxsv5 \LaravelS \Swoole \Task \Listener ;class TestListener1 extends Listener { public function __construct ( ) { } public function handle (Event $event ) { \Log ::info (__CLASS__ . ':handle start' , [$event ->getData ()]); sleep (2 ); $ret = Task ::deliver (new TestTask ('task data' ), true ); var_dump ($ret ); } }
绑定事件与监听器
1 2 3 4 5 6 7 8 9 10 11 [ 'events' => [ \App\Tasks\TestEvent ::class => [ \App\Tasks\TestListener ::class , ], ], ];
触发事件
1 2 3 4 5 6 use Hhxsv5 \LaravelS \Swoole \Task \Event ;$success = Event ::fire (new TestEvent ('event data' ));var_dump ($success );
异步的任务队列
此特性依赖Swoole
的AsyncTask
,必须先设置config/laravels.php
的swoole.task_worker_num
。 异步事件的处理能力受Task进程数影响,需合理设置task_worker_num 。
创建任务类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <?php namespace App \Tasks ;use Hhxsv5 \LaravelS \Swoole \Task \Task ;use Illuminate \Support \Facades \Log ;class TestTask extends Task { private $data ; private $result ; public function __construct ($data ) { $this ->data = $data ; } public function handle ( ) { \Log ::info (__CLASS__ . ':handle start' , [$this ->data]); sleep (2 ); $this ->result = 'the result of' . $this ->data; } public function finish ( ) { \Log ::info (__CLASS__ . ':finish start' , [$this ->result]); Task ::deliver (new TestTask2 ('task2' )); } }
投递任务
1 2 3 4 5 6 7 8 use Hhxsv5 \LaravelS \Swoole \Task \Task ;$task = new TestTask ('task data' );$ret = Task ::deliver ($task );var_dump ($ret );
毫秒级定时任务
基于Swoole的毫秒定时器 ,封装的定时任务,取代Linux
的Crontab
。
创建定时任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 <?php namespace App \Jobs \Timer ;use App \Tasks \TestTask ;use Hhxsv5 \LaravelS \Swoole \Timer \CronJob ;use Hhxsv5 \LaravelS \Swoole \Task \Task ;class TestCronJob extends CronJob { protected $i = 0 ; public function interval ( ) { return 1000 ; } public function isImmediate ( ) { return false ; } public function run ( ) { \Log ::info (__METHOD__ , ['start' , $this ->i, microtime (true )]); $this ->i++; \Log ::info (__METHOD__ , 'end' , $this ->i, microtime (true )); if ($this ->i >= 10 ) { \Log ::info (__METHOD__ , ['stop' , $this ->i, microtime (true )]); $this ->stop (); $ret = Task ::deliver (new TestTask ('task data' ), true ); var_dump ($ret ); } } }
注册定时任务类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 [ 'timer' => [ 'enable' => true , 'jobs' => [ \App\Jobs\Timer\TestCronJob ::class , ], ], ];
注意在构建服务器集群时,会启动多个定时器
,要确保只启动一个定期器,避免重复执行定时任务
修改代码后自动Reload
安装inotify
扩展
开启配置项
注意:inotify
只有在Linux
内修改文件才能收到文件变更事件,建议使用最新版Docker,Vagrant解决方案。
基于fswatch
,支持OS X、Linux、Windows。
安装fswatch
在项目根目录下运行命令。
CentOS下安装fawatch
1 2 3 4 5 wget https: cd fswatch-1.13 .0 ./configure make && make install
在项目中使用swoole_server
实例 1 2 3 4 5 6 $swoole = app ('swoole' );var_dump ($swoole ->stats ());
使用swoole_table
定义swoole_table
, 支持定义多个Table
Swoole启动之前会创建定义的所有Table。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 'swoole_tables' => [ 'ws' => [ 'size' => 102400 , 'column' => [ [ 'name' => 'value' , 'type' => \swoole_table::TYPE_INT , 'size' => 8 , ], ], ], ],
2.访问swoole_table
:所有的Table实例均绑定在swoole_server
上,通过app('swoole')->xxxTable
访问。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public function onOpen (\swoole_websocket_server $server , \swoole_http_request $request ) { $userId = mt_rand (1000 , 10000 ); app ('swoole' )->wsTable->set ('uid:' . $userId , ['value' => $request ->fd]); app ('swoole' )->wsTable->set ('fd:' . $request ->fd, ['value' => $userId ]); $server ->push ($request ->fd, 'Welcome to LaravelS' ); } public function onMessage (\swoole_websocket_server $server , \swoole_websocket_frame $frame ) { foreach (app ('swoole' )->wsTable as $key => $row ) { if (strpos ($key , 'uid:' ) === 0 && $server ->exist ($row ['value' ])) { $server ->push ($row ['value' ], 'Broadcast: ' . date ('Y-m-d H:i:s' )); } } } public function onClose (\swoole_websocket_server $server , $fd , $reactorId ) { $uid = app ('swoole' )->wsTable->get ('fd:' . $fd ); if ($uid !== false ) { app ('swoole' )->wsTable->del ('uid:' . $uid ['value' ]); } app ('swoole' )->wsTable->del ('fd:' . $fd ); $server ->push ($fd , 'Goodbye' ); }
多端口混合协议
更多的信息,请参考Swoole增加监听的端口与多端口混合协议
为了使我们的主服务器能支持除HTTP
和WebSocket
外的更多协议,我们引入了Swoole
的多端口混合协议特性,在LaravelS
中称为Socket
。 现在,可以很方便地在Laravel上被构建TCP/UDP应用。
创建Socket
处理类,继承Hhxsv5\LaravelS\Swoole\Socket\{TcpSocket|UdpSocket|Http|WebSocket}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <?php namespace App \Sockets ;use Hhxsv5 \LaravelS \Swoole \Socket \TcpSocket ;class TestTcpSocket extends TcpSocket { public function onConnect (\swoole_server $server , $fd , $reactorId ) { \Log ::info ('New TCP connection' , [$fd ]); $server ->send ($fd , 'Welcome to LaravelS' ); } public function onReceive (\swoole_server $server , $fd , $reactorId , $data ) { \Log ::info ('Received data' , [$fd , $data ]); $server ->send ($fd , 'LaravelS:' . $data ); if ($data === "quit\r\n" ) { $server ->send ($fd , 'LaravelS: bye' . PHP_EOL); $server ->close ($fd ); } } public function onClose (\swoole_server $server , $fd , $reactorId ) { \Log ::info ('Close TCP connection' , [$fd ]); $server ->send ($fd , 'GoodBye' ); } }
这些连接和主服务器上的HTTP
/WebSocket
连接共享Worker
进程,因此可以在这些事件操作中使用LaravelS
提供的异步任务投递
、swoole_table
、Laravel
提供的组件如DB
、Eloquent
等。同时, 如果需要使用该协议端口的swoole_server_port
对象,只需要像如下代码一样访问Socket
类的成员swoolePort
即可。
1 2 3 4 public function onReceive (\swoole_server $server , $fd , $reactorId , $data ) { $port = $this ->swoolePort; }
注册套接字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 'sockets' => [ [ 'host' => '127.0.0.1' , 'port' => 5291 , 'type' => SWOOLE_SOCK_TCP, 'settings' => [ 'open_eof_check' => true , 'package_eof' => "\r\n" , ], 'handler' => \App\Sockets\TestTcpSocket ::class , ], ],
关于心跳配置,只能设置在主服务器
上,不能配置在套接字
上,但套接字
会继承 主服务器
的心跳配置。
对于TCP协议,dispatch_mode
选项设为1/3
时,底层会屏蔽onConnect/onClose
事件,原因是这两种模式下无法保证onConnect
/onClose
/onReceive
的顺序。 如果需要用到这两个事件,请将dispatch_mode
改为2/4/5
,参考。
1 2 3 4 5 'swoole' => [ 'dispatch_mode' => 2 , ];
测试
TCP: telnet 127.0.0.1 5291
UDP: Linux下 echo "Hello LaravelS" > /dev/udp/127.0.0.1/5292
其他协议的注册示例
UDP
1 2 3 4 5 6 7 8 9 10 11 12 'sockets' => [ [ 'host' => '0.0.0.0' , 'port' => 5292 , 'type' => SWOOLE_SOCK_UDP, 'settings' => [ 'open_eof_check' => true , 'package_eof' => "\r\n" , ], 'handler' => \App\Sockets\TestUdpSocket ::class , ], ],
HTTP
1 2 3 4 5 6 7 8 9 10 11 'sockets' => [ [ 'host' => '0.0.0.0' , 'port' => 5293 , 'type' => SWOOLE_SOCK_TCP, 'settings' => [ 'open_http_protocol' => true , ], 'handler' => \App\Sockets\TestHttp ::class , ], ],
WebSocket
1 2 3 4 5 6 7 8 9 10 11 12 'sockets' => [ [ 'host' => '0.0.0.0' , 'port' => 5294 , 'type' => SWOOLE_SOCK_TCP, 'settings' => [ 'open_http_protocol' => true , 'open_websocket_protocol' => true , ], 'handler' => \App\Sockets\TestWebSocket ::class , ], ],
协程
Swoole - 协程(Coroutine)
警告:Laravel/Lumen中存在大量单例和静态属性,在协程下是不安全
的,不建议打开协程。
启用协程,默认是关闭的
1 2 3 4 5 6 7 8 [ 'swoole' => [ 'enable_coroutine' => true ], ]
1 2 3 4 5 [ 'enable_coroutine_runtime' => true ]
自定义进程
支持开发者创建一些特殊的工作进程,用于监控、上报或者其他特殊的任务,参考addProcess 。
创建Process
类,实现CustomProcessInterface
接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 <?php namespace App \Processes ;use Hhxsv5 \LaravelS \Swoole \Process \CustomProcessInterface ;use App \Tasks \TestTask ;use Hhxsv5 \LaravelS \Swoole \Task \Task ;class TestProcess implements CustomProcessInterface { public static function getName ( ) { return 'test' ; } public static function isRedirectStdinStdout ( ) { return false ; } public static function getPipeType ( ) { return 0 ; } public static function callback (\swoole_server $swoole ) { \Log ::info (__METHOD__ , [posix_getpid (), $swoole ->stats ()]); while (true ) { \Log ::info ('Do something' ); sleep (1 ); $ret = Task ::deliver (new TestTask ('task data' ), true ); var_dump ($ret ); } } }
注册TestProcess
1 2 3 4 5 'processes' => [ \App\Processes\TestProcess ::class , ],
注意: TestProcess::callback()
方法不能退出, 如果退出次数达到10次,Manager进程将会重新创建进程
其他特性 配置Swoole
的事件回调函数 支持的事件列表:
事件
需实现的接口
发生时机
WorkerStart
Hhxsv5\LaravelS\Swoole\Events\WorkerStartInterface
发生在Worker进程/Task进程启动时,并且已经完成Laravel初始化
创建事件处理类,实现相应的接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?php namespace App \Events ;use Hhxsv5 \LaravelS \Swoole \Events \WorkerStartInterface ;class WorkerStartEvent implements WorkerStartInterface { public function __construct ( ) { } public function handle (\swoole_http_server $server , $workerId ) { if (!isset ($server ->connectionPool)) { $server ->connectionPool = new ConnectionPool (); } } }
配置
1 2 3 4 'event_handlers' => [ 'WorkerStart' => \App\Events\WorkerStartEvent ::class , ],
注意事项 单例问题
常见问题
应通过Illuminate\Http\Request
对象来获取请求信息,$_ENV
是可读取的,$_SERVER
是部分可读的, 不能使用$_GET
、$_POST
、$_FILES
、$_COOKIE
、$_REQUEST
、$_SESSION
、$GLOBALS
。
1 2 3 4 5 6 7 8 9 10 use Illuminate \Http \Request ;public function test_form (Request $request ) { $name = $request ->input ('name' ); $all = $request ->all (); $sessionId = $request ->cookie ('sessionId' ); $photo = $request ->file ('photo' ); $rawContent = $request ->getContent (); }
推荐通过返回Illuminate\Http\Response
对象来响应请求, 兼容echo
、var_dump()
、print_r()
, 不能使用函数像 dd()
、exit()
、die()
、header()
、setcookie()
、http_response_code()
。
1 2 3 4 5 6 7 8 public function json ( ) { return response ()->json ([ 'time' => time () ]) ->header ('header1' , 'value1' ) ->withCookie ('c1' , 'v1' ); }
各种单例的连接
将被常驻内存,建议开启持久连接
。
数据库连接,连接断开后会自动重连
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 'connections' => ['my_conn' => [ 'driver' => 'mysql' , 'host' => env ('DB_MY_CONN_HOST' , 'localhost' ), 'port' => env ('DB_MY_CONN_PORT' , 3306 ), 'database' => env ('DB_MY_CONN_DATABASE' , 'forge' ), 'username' => env ('DB_MY_CONN_USERNAME' , 'forge' ), 'password' => env ('DB_MY_CONN_PASSWORD' , '' ), 'charset' => 'utf8mb4' , 'collation' => 'utf8mb4_unicode_ci' , 'prefix' => '' , 'strict' => false , 'options' => [ \PDO::ATTR_PERSISTENT => true , ], ],
Redis
连接,连接断开后不会立即
自动重连,会抛出一个关于连接断开的异常,下次会自动重连。需确保每次操作Redis前正确的SELECT DB
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 'redis' => [ 'client' => 'predis' , 'default' => [ 'host' => env ('REDIS_HOST' , '127.0.0.1' ), 'password' => env ('REDIS_PASSWORD' , null ), 'port' => env ('REDIS_PORT' , 6379 ), 'database' => env ('REDIS_DB' , 0 ), 'persistent' => true , ], 'cache' => [ 'host' => env ('REDIS_HOST' , '127.0.0.1' ), 'password' => env ('REDIS_PASSWORD' , null ), 'port' => env ('REDIS_PORT' , 6379 ), 'database' => env ('REDIS_CACHE_DB' , 1 ), ], ],
你声明的全局、静态变量必须手动清理或重置。
无限追加元素到静态或全局变量中,将导致内存爆满。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Test { public static $array = []; public static $string = '' ; } public function test (Request $req ) { Test ::$array [] = $req ->input ('param1' ); Test ::$string .= $req ->input ('param2' ); }