用 Convert 在連 Server 時,就會出現 SSH Error
總之就是 SSH 加密升級造成的問題
參考這篇討論
https://communities.vmware.com/t5/VMware-vSphere-Discussions/SCP-between-4-1-and-6-7/td-p/490986
用 Convert 在連 Server 時,就會出現 SSH Error
總之就是 SSH 加密升級造成的問題
參考這篇討論
https://communities.vmware.com/t5/VMware-vSphere-Discussions/SCP-between-4-1-and-6-7/td-p/490986
Gentoo 官方的 portage 沒有 scrcpy 這軟體,必須找 overlay 的 ebuild。
安裝好後,第一次執行
ajax@aj-i7 ~ $ scrcpy
INFO: scrcpy 1.17 <https://github.com/Genymobile/scrcpy>
exec: No such file or directory
ERROR: Command not found: [adb], [push], [/usr/share/scrcpy/scrcpy-server], [/data/local/tmp/scrcpy-server.jar]
ERROR: (make 'adb' accessible from your PATH or define its fullpath in the ADB environment variable)
INFO: You may install 'adb' by "apt install adb"
ERROR: Could not execute "adb push"找不到 adb 指令,關於 Gentoo 的 adb 說明: Android/adb
安裝 dev-util/android-tools package 之後再執行
ajax@aj-i7 ~ $ scrcpy
INFO: scrcpy 1.17 <https://github.com/Genymobile/scrcpy>
* daemon not running; starting now at tcp:5037
* daemon started successfully
adb: error: failed to get feature set: no devices/emulators found
ERROR: "adb push" returned with value 1需要在手機開啟 USB debug,這個無需 root,一般是在 [系統資訊] 的某個項目上點 7下,就會出現開發者選項。
再次執行
ajax@aj-i7 ~ $ scrcpy
INFO: scrcpy 1.17 <https://github.com/Genymobile/scrcpy>
/usr/share/scrcpy/scrcpy-server: 1 fil...shed. 1.3 MB/s (34930 bytes in 0.025s)
[server] INFO: Device: samsung SM-A315G (Android 10)
[server] ERROR: Exception on thread Thread[main,5,main]
java.lang.IllegalStateException
at android.media.MediaCodec.native_dequeueOutputBuffer(Native Method)
at android.media.MediaCodec.dequeueOutputBuffer(MediaCodec.java:2789)
at com.genymobile.scrcpy.ScreenEncoder.encode(ScreenEncoder.java:113)
at com.genymobile.scrcpy.ScreenEncoder.internalStreamScreen(ScreenEncoder.java:94)
at com.genymobile.scrcpy.ScreenEncoder.streamScreen(ScreenEncoder.java:60)
at com.genymobile.scrcpy.Server.scrcpy(Server.java:80)
at com.genymobile.scrcpy.Server.main(Server.java:252)
at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:342)
INFO: Renderer: opengl
INFO: OpenGL version: 4.6.0 NVIDIA 460.56
INFO: Trilinear filtering enabled
INFO: Initial texture: 1080x2400
WARN: Device disconnected還是不行,但只差一步了,指令要加解析度
ajax@aj-i7 ~ $ scrcpy -m 1080
INFO: scrcpy 1.17 <https://github.com/Genymobile/scrcpy>
/usr/share/scrcpy/scrcpy-server: 1 fil...shed. 5.6 MB/s (34930 bytes in 0.006s)
[server] INFO: Device: samsung SM-A315G (Android 10)
INFO: Renderer: opengl
INFO: OpenGL version: 4.6.0 NVIDIA 460.56
INFO: Trilinear filtering enabled
INFO: Initial texture: 488x1080
==> 連上手機,開啟手機螢幕視窗
....
==> 關閉手機螢幕視窗
WARN: Killing the server...旋轉90度的指令 "scrcpy -m 1080 --lock-video-orientation 1"
media-sound/jack2
FROM centos:7.9.2009
RUN yum -y install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm \
&& yum -y update \
&& yum -y install --enablerepo=remi,remi-php70 \
httpd php php-pdo php-pgsql \
php-xml php-mbstring php-mcrypt \
php-opcache php-pecl-swoole2 php-pecl-inotify \
unzip supervisor \
&& yum clean all \
&& rm -rf /var/cache/yum \
&& curl -o /usr/bin/composer https://getcomposer.org/download/1.10.20/composer.phar \
&& chmod a+x /usr/bin/composer
# add config file
COPY conf/httpd.conf /etc/httpd/conf/httpd.conf
COPY conf/supervisord.conf /etc/supervisord.conf
COPY conf/rev_proxy.conf /etc/httpd/conf.d/
#port and entry
EXPOSE 80
CMD ["/usr/bin/supervisord"]
其中,php-pecl-swoole2 為 PHP 加 Swoole 功能,php-pecl-inotify 則是為了偵測檔案變動重新載入程式。
<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>
RemoteIPHeader X-Forwarded-For
ProxyRequests Off
ProxyPreserveHost On
[supervisord]
nodaemon=true
logfile=/var/log/supervisord.log
pidfile=/var/run/supervisord.pid
[program:ntuocw_laravels]
command=php /var/www/html/ntu-ocw/web-src/bin/laravels start
redirect_stderr=true
autostart=true
autorestart=true
#user=http
numprocs=1
process_name=%(program_name)s_%(process_num)s
stdout_logfile=/var/www/html/ntu-ocw/storage/logs/bin_laravel-s-log1.log
stdout_logfile_maxbytes=1MB
stdout_logfile_backups=5
[program:httpd]
redirect_stderr=true
command=/usr/sbin/httpd -DFOREGROUND
process_name = httpd
docker-compose build ==> 建立 image
docker-compose up ==> 啟動
docker-compose up -d ==> 啟動,在背景執行
docker-compose down ==> 停止
version: '2'
services:
web:
build:
context: ./
# dockerfile: Swoole_dockerfile
restart: always
working_dir: /var/www/html
volumes:
- ../web:/var/www/html
- ../work_tmp:/work_tmp
environment:
COMPOSER_HOME: /work_tmp/Composer
ports:
- 8180:80
docker exec -it --user 1000:1000 ocw_docker_web_1 bash
composer create-project laravel/laravel ntu-ocw "5.1.*""require": {
"php": ">=5.5.9",
"laravel/framework": "5.1.*",
"hhxsv5/laravel-s": "3.6.*"
},
'providers' => [
//...
Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider::class,
],
php artisan laravels publish
若出現無法寫入 storage 的檔案時,
sudo chmod -R a+w storage/
config/laravels.php
bin/laravels
bin/fswatch
bin/inotify
DirectoryIndex index.php ==> Apache 預設為 index.html
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ http://localhost:10520/$1 [P,L]
# configs for Laravel-S
LARAVELS_LISTEN_PORT=10520
LARAVELS_WORKER_NUM=5
LARAVELS_INOTIFY_RELOAD=true PID TTY STAT TIME COMMAND
1 ? Ss 0:01 /usr/bin/python /usr/bin/supervisord
8 ? Sl 0:00 /var/www/html/ntu-ocw/web-src laravels: master process
9 ? S 0:00 /usr/sbin/httpd -DFOREGROUND
22 ? S 0:00 /var/www/html/ntu-ocw/web-src laravels: manager process
28 ? S 0:00 /var/www/html/ntu-ocw/web-src laravels: worker process 0
29 ? S 0:00 /var/www/html/ntu-ocw/web-src laravels: worker process 1
30 ? S 0:00 /var/www/html/ntu-ocw/web-src laravels: worker process 2
31 ? S 0:00 /var/www/html/ntu-ocw/web-src laravels: worker process 3
32 ? S 0:10 /var/www/html/ntu-ocw/web-src laravels: worker process 4
33 ? S 0:00 /var/www/html/ntu-ocw/web-src laravels: inotify process
72 pts/0 Ss 0:00 bash
111 ? S 0:00 /usr/sbin/httpd -DFOREGROUND
203 ? Z 0:00 [httpd] <defunct>
227 ? S 0:01 /usr/sbin/httpd -DFOREGROUND
........
265 ? S 0:00 /usr/sbin/httpd -DFOREGROUND
266 pts/0 R+ 0:00 ps -ax
'inotify_reload' => [
'enable' => env('LARAVELS_INOTIFY_RELOAD', false),
'watch_path' => base_path(),
'file_types' => ['.php', '.env'],
'excluded_dirs' => [],
'log' => true,
],
class AppServiceProvider extends ServiceProvider
{
// Bootstrap any application services.
public function boot()
{
// 送交 Laravel 前的處理
\Event::listen('laravels.received_request', function (\Illuminate\Http\Request $req, $app) {
// 這裡才是真的透過 browser瀏覽
// 才有某些關於 client 的 SERVER 資料
\App\Lib\SW_util::boot_setup($req, $app);
});
// Laravel 結束後的處理
\Event::listen('laravels.generated_response', function (\Illuminate\Http\Request $req, \Symfony\Component\HttpFoundation\Response $rsp, $app) {
// $rsp->headers->set('Content-Type', 'image/png');// Change header of response
});
}
// boot() 的啟始程序
public static function boot_setup(\Illuminate\Http\Request $req, $app)
{
// 在這裡 print 的訊息,都會出現在執行 laravels start 的 console
// echo "\n\n===== laravels.received_request =====\n";
session()->clear();
// 去除附加的預設執行檔 index.php
$req_uri = $req->server->get("REQUEST_URI");
$d_php = '/index.php'; // 配合 .htaccess 的 DirectoryIndex 設定
if (starts_with($req_uri, $d_php)) {
$req_uri = substr($req_uri, strlen($d_php));
if ($req_uri == '') {
$req_uri = '/';
}
$req->server->set("REQUEST_URI", $req_uri);
}
// 把 IP 改成實際的 remote IP
$req->server->set("REMOTE_ADDR", $req->server->get("HTTP_X_FORWARDED_FOR"));
// $_SERVER["SCRIPT_FILENAME"] =>
// "/var/www/html/ajtest/ntu-ocw/web-src/bin/laravels"
$pre_s = '/var/www/html/';
$tail_s = '/web-src/bin/laravels';
$url_path = substr($req->server->get("SCRIPT_NAME"), strlen($pre_s));
$url_path = substr($url_path, 0, (0-strlen($tail_s)));
\URL::forceRootUrl('http://'.$req->server->get('HTTP_HOST').'/'.$url_path);
self::$dump_handler = null;
}
在剛開始設定 Laravel-S 可以連線時,要開啟目錄的預設網頁時,一直會出現無法 match route 的錯誤,真是讓人感到挫折灰心。後來根據錯誤訊息,追縱 Laravel 的原始碼,直接找到 Illuminate\Routing\Router.php,在出錯的那個 function,把傳過來 url 列印出來,才發現收到的 httpd 送來的預設檔名,index.html,後來自己改成 index.php。在執行 match route 之前必須將 index.php 移除。在 Symfony 中,有相關程式的片段。
將系統切換之後,在測試留言功能時,發現怎麼我第一次用,就有亂七八糟的留言內容,並且顯示驗證碼錯誤。再仔細檢查,不得了,所有的 session 內容全部變成一樣了,裡面還有我剛剛登入管理端的帳號身份。因為下班後才發現,只好把系統先關掉,將 session 全刪掉,再重新啟動系統。使用者不能留言,也就只好忍耐一下囉,終究先前曾經因系統設定錯誤,一兩個月留言功能都不正常,也沒人反應。
短時間內,找不到其他使用者的相關經驗分享,或是 Laravel-S 對 session 處理的相關說明。就先自己追蹤程式吧,發現是 Laravel 的 session/store.php 中,會將 attributes 陣列的資料與儲存的 session 資料合併。而 Session store 只在 laravel-s start 時 Instance 一次,因而其 attributes array 會保留前一次連線的 session 資料。幸好此系統僅是供使用者瀏覽,只有一個網頁讓使用者留言用,session 不正確沒有造成太大的影響。
Laravel 框架是使用 Symfony 的 Session,其 Session Store 是 Implement Symfony 的 SessionInterface。在實際運作時,建立的 session 資料是放在 attributes 陣列中,等到連線結束時,才寫回儲存裝置中。在緊急情況下,直接修改 store.php,在 function start() 中直接將 attributes 陣列清空。後來找到 interface 中有提供 function clear(),其功能即是將 attributes 陣列清空。
要取得 session 物件有幾種方式,session() 或 $req->session(),在 boot 時, session 還沒加進 $req 中,呼叫 $req->session() 會出現錯誤 "Session store not set on request"。還好可以正常呼叫 session()->clear(), 將 attributes 陣列清除。
依照上面的作法,將問題解決了。過了一陣子,隨意搜尋關於 Larave-S 的資訊,發現早就有人反應此問題,甚至在最早查資料時,就曾看過有關的敘述,只是那時一點概念都沒有,不曉得他在說什麼。而且 Larave-S 也解決了此問題,在 setting 中有相關說明,只是自己不能理解。
解決辦法很簡單,在 config/laravels.php 中的 'cleaners' 加入設定即可。
// Need to configure the following cleaners if you use the session/authentication/passport in your project
'cleaners' => [
Hhxsv5\LaravelS\Illuminate\Cleaners\SessionCleaner::class,
Hhxsv5\LaravelS\Illuminate\Cleaners\AuthCleaner::class,
],
這樣就可以了,就這麼簡單,真是踏破鐵鞋方覓得,嗯,頂多是多按了一些鍵盤啦。
調整後的目錄大致是這樣
ntu-ocw
+- assets
| +- css, js, img, .....
+- vendor
| +- hhxsv5, laravel, .....
+- storage
| +- app, framework, logs, ....
+- web-src
| +- bin, app, config, ....
| +- storage (僅供 laravels 存放資料 laravels.json laravels.pid)
+ .htaccess, favicon.ico, robots.txt
"config": {
"preferred-install": "dist",
"vendor-dir": "../vendor"
}
// $basePath = realpath(__DIR__ . '/../');
// BASEDIR, VENDORDIR 同時要定義在 artisan 中
define('BASEDIR', realpath(__DIR__ . '/../'));
define('VENDORDIR', realpath(__DIR__.'/../../vendor'));
$loader = new Psr4Autoloader();
$loader->register();
// Register laravel-s
$loader->addNamespace('Hhxsv5\LaravelS', VENDORDIR . '/hhxsv5/laravel-s/src');
// Register laravel-s dependencies
$loader->addNamespace('Symfony\Component\Console', VENDORDIR . '/symfony/console');
$loader->addNamespace('Symfony\Contracts\Service', VENDORDIR . '/symfony/service-contracts');
$loader->addNamespace('Symfony\Contracts', VENDORDIR . '/symfony/contracts');
$command = new Hhxsv5\LaravelS\Console\Portal(BASEDIR);
$input = new Symfony\Component\Console\Input\ArgvInput();
$output = new Symfony\Component\Console\Output\ConsoleOutput();
$code = $command->run($input, $output);
exit($code);
define('BASEDIR', __DIR__.'');
define('VENDORDIR', realpath(__DIR__.'/../vendor'));
require BASEDIR.'/bootstrap/autoload.php';
$app = require_once BASEDIR.'/bootstrap/app.php';
$app->useStoragePath(realpath(BASEDIR.'/../storage'));
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);
$app->useStoragePath(realpath(BASEDIR.'/../storage'));
require VENDORDIR.'/autoload.php';
花了這麼多時間了解,查資料,追蹤,思考,測試,除錯,才把系統套到 Laravel-S,用上 Swoole 加速的功能,總會想了解花費的心血得到多少的收益。若是收效不大,大可不用,造成維護上的麻煩。
下面先用 siege 做壓力測試,看看網站每秒最多能處理多少連線。再用 curl 觀察個別連線花費的時間。
$ siege -c 100 -t 5s http://ocw.aca.ntu.edu.tw/ntu-ocw/ > /dev/null
** SIEGE 4.0.7
** Preparing 100 concurrent users for battle.
The server is now under siege...
Lifting the server siege...
Transactions: 769 hits
Availability: 100.00 %
Elapsed time: 4.54 secs
Data transferred: 14.84 MB
Response time: 0.56 secs
Transaction rate: 169.38 trans/sec
Throughput: 3.27 MB/sec
Concurrency: 94.54
Successful transactions: 769
Failed transactions: 0
Longest transaction: 1.65
Shortest transaction: 0.03
$ siege -c 100 -t 5s http://ocw.aca.ntu.edu.tw:8180/ntu-ocw/ > /dev/null
** SIEGE 4.0.7
** Preparing 100 concurrent users for battle.
The server is now under siege...
Lifting the server siege...
Transactions: 863 hits
Availability: 100.00 %
Elapsed time: 4.28 secs
Data transferred: 27.31 MB
Response time: 0.40 secs
Transaction rate: 201.64 trans/sec
Throughput: 6.38 MB/sec
Concurrency: 81.50
Successful transactions: 863
Failed transactions: 0
Longest transaction: 2.98
Shortest transaction: 0.00
$ siege -c 100 -t 5s http://10.161.86.117:8180/ntu-ocw/ > /dev/null
** SIEGE 4.0.7
** Preparing 100 concurrent users for battle.
The server is now under siege...
Lifting the server siege...
Transactions: 30103 hits
Availability: 100.00 %
Elapsed time: 4.05 secs
Data transferred: 1053.04 MB
Response time: 0.01 secs
Transaction rate: 7432.84 trans/sec
Throughput: 260.01 MB/sec
Concurrency: 98.84
Successful transactions: 30103
Failed transactions: 0
Longest transaction: 0.25
Shortest transaction: 0.00
$ siege -c 100 -t 5s http://10.161.86.117:8080/ajtest/ntu-ocw/ > /dev/null
** SIEGE 4.0.7
** Preparing 100 concurrent users for battle.
The server is now under siege...
Lifting the server siege...
Transactions: 2664 hits
Availability: 100.00 %
Elapsed time: 4.03 secs
Data transferred: 361.01 MB
Response time: 0.15 secs
Transaction rate: 661.04 trans/sec
Throughput: 89.58 MB/sec
Concurrency: 97.29
Successful transactions: 2664
Failed transactions: 0
Longest transaction: 0.31
Shortest transaction: 0.03
在測試環境得到結果,使用 Swoole 加速每秒大約可以處理 10倍的連線。對了,在這網頁有用到 Laravel 的 cache 功能,會將資料庫查詢 cache 在檔案中,因此不受資料庫效能的影響。
#!/bin/bash
curl -w @- -o /dev/null -s "$@" <<'EOF'
time_namelookup: %{time_namelookup}\n
time_connect: %{time_connect}\n
time_appconnect: %{time_appconnect}\n
time_pretransfer: %{time_pretransfer}\n
time_redirect: %{time_redirect}\n
time_starttransfer: %{time_starttransfer}\n
----------\n
time_total: %{time_total}\n
EOF
$ ./curltime http://140.112.161.116/ntu-ocw/
time_namelookup: 20
time_connect: 2286
time_appconnect: 0
time_pretransfer: 2303
time_redirect: 0
time_starttransfer: 19828
----------
time_total: 30103
$ ./curltime http://140.112.161.116:8180/ntu-ocw/
time_namelookup: 92
time_connect: 2724
time_appconnect: 0
time_pretransfer: 2739
time_redirect: 0
time_starttransfer: 94360
----------
time_total: 101133
從結果的數來看,時間單位應是 microseconds。
為了減少 DNS 查詢時間,使用 IP 連線。花費的時間會一直變動,使用 Swoole 加速,每個連線花費的時間大約在 30ms 左右。而未加速時,花費時間大約為 100ms 左右。
以上使用正式開放的網站測試,可能受網站安全防護或其他使用者連線的影響。接著使用測試環境來測試,比較能看到純粹網站的效能。
$ ./curltime http://10.161.86.117:8180/ntu-ocw/
time_namelookup: 89
time_connect: 295
time_appconnect: 0
time_pretransfer: 400
time_redirect: 0
time_starttransfer: 13112
----------
time_total: 13402
$ ./curltime http://10.161.86.117:8080/ajtest/ntu-ocw/
time_namelookup: 17
time_connect: 70
time_appconnect: 0
time_pretransfer: 110
time_redirect: 0
time_starttransfer: 23723
----------
time_total: 24125
在測試了最熱門的 swooletw/laravel-swoole 不成功之後,再測熱門程度差了好幾個等級,甚至 Google "laravel swoole" 的關鍵字,在搜尋結果都不會出現的 hhxsv5/laravel-s,成功了,那就繼續探所下去吧。
首先,新手真的不曉得該如 rewrite rule,轉過來的 request,有啟動 php 程式,但一直出 match route 錯誤,真是讓人感到挫折灰心。後來根據錯誤訊息,追縱 Laravel 的原始碼,直接找到 Illuminate\Routing\Router.php,在出錯的那個 function,加上下列程式片段,這樣它就會在執行的命令視窗顯示轉過來的網址,再依此結果修正 rewrite rule。
findRoute($request)
{
echo "findRoute\n";
var_dump($request->getRequestUri()); exit;
....
} DirectoryIndex index.php
Route::get('/index.php', function () { ... });
解決辦法,參考原程式,自己另建一個 dump()
static 變數的測試,噢,會互相影響,所以要改很多 ...,只能再看看吧!!
另一困擾,假如網頁不是放在伺服器的 DocumentRoot 目錄下,asset() 和 url() 不會加上網頁的目錄,如 http://ll.cc/blog/list ...,其中 blog 不會出現。這要改的也是不少。
public function boot()
{
\URL::forceRootUrl("http://localhost:8180/blog");
}
亦可將其定義在 .env 中,例如 APP_URL。只要加上兩行就能解決問題,算是不錯了。
/*
* 此為 laravels.received_request, After LaravelS parsed Swoole\Http\Request
* to Illuminate\Http\Request, before Laravel's Kernel handles this request.
*/
public function boot()
{
// 只會在 loading 時被 call 一次
echo "===================\n";
\Event::listen('laravels.received_request',
function (\Illuminate\Http\Request $req, $app)
{
// 這裡才是真的透過 browser瀏覽
// 才有某些關於 client 的 SERVER 資料
// 去除附加的預設執行檔 index.php
$req_uri = $req->server->get("REQUEST_URI");
$def_php = '/index.php';
if (substr($req_uri, 0, strlen($def_php)) == $def_php) {
$req_uri = substr($req_uri, strlen($def_php));
if ($req_uri == '') {
$req_uri = '/';
}
$req->server->set("REQUEST_URI", $req_uri);
}
// 看起來,root url 並不是依據 "HTTP_HOST" 產生的
// 改變 "HTTP_HOST",並不會改變 url() 和 asset() 的結果
// 但是又找不到其他變數含有 port 資料
// $req_host = $req->server->get("HTTP_HOST");
// echo $req_host."<br>\n";
// $req->server->set("HTTP_HOST", $req_host.'abc');
// $req->server->set("HTTP_HOST", env('URL_PATH'));
var_dump($req->request->all());
echo base_path()."<br>\n";
// initialize static varibles
Util_sw::clean();
// $req->query->set('get_key', 'hhxsv5');// Change query of request
// $req->request->set('post_key', 'hhxsv5'); // Change post of request
// echo asset(env('URL_PATH'))."<br>\n";
\URL::forceRootUrl('http://'.$req->server->get('HTTP_HOST').'/'.env('URL_PATH'));
}
);
// echo request()->getPathInfo();
// echo \URL::to('/')."<br>\n";
// var_dump(getallheaders());
// \URL::forceRootUrl(env("APP_URL"));
}在上面的程式片段中,加了一堆測試輸出訊息的程式,就是在摸索階段為了瞭解其特性而加的。其餘的再繼續整理中。
依照 Laravel-S 專案上的說明,將 Laravel 的 .htaccess 的內容修改如下,就是在檔案不存在時,轉到 laravel-s 伺服程式處理。而 Apache 的 httpd,在瀏覽目錄時,設定的預設程式是 index.html,在這裡把它改成 index.php。
# Alternate default index page
DirectoryIndex index.php
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
RewriteEngine On
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ balancer://laravels/$1 [P,L]
</IfModule><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>
RemoteIPHeader X-Forwarded-For
ProxyRequests Off
ProxyPreserveHost On
<Proxy balancer://laravels>
BalancerMember http://127.0.0.1:5200 loadfactor=7
#BalancerMember http://192.168.1.2:5200 loadfactor=3
#BalancerMember http://192.168.1.3:5200 loadfactor=1 status=+H
ProxySet lbmethod=byrequests
</Proxy>
因為一個伺服器不只一個網頁程式,所以並未依照 Laravel-S 的說明,將網頁指向根目錄 (/)。為了解決此問題,測試了好久才搞定。
另外,不想修改網站設定,依自己的習慣調網站的目錄架構,將 public 目錄下的東西移到網頁的根目錄,程式則移到 web-src 下面,storage 不太好移,仍然放在 web-src 下,所以還需進一步修改 bin/laravels.php、artisan,bootstrap/autoload.php。
後續發展,經過半個多月的摸索,終於將一個自己維護的網站套上 Laravel-S 了,後面再開一篇文章來整理修改和注意的重點。
Swoole 這名稱聽過好一陣子了,但聽起來感覺不怎麼特別,另外也沒有特別要求速度的網頁,或者使用的 OS 是老掉牙的 Windows Server 2003,就沒什麼很注意。最近稍有空閒,想找點新東西來玩玩,活絡一下大腦,才稍微深入研究探討。
首先看一下執行的畫面,嗯,網頁主要是有個圖比較好看。
現代程式開發人員的好處就是,不用在自己日常用的電腦上裝一堆不知有沒有的軟體來測試新的東西,只要寫個 docker 的設定檔,就可以弄一個測試環境。測試 Swoole 的 Dockerfile 如下。
FROM centos:7.9.2009
RUN yum -y install \
http://rpms.famillecollet.com/enterprise/remi-release-7.rpm \
&& yum -y install --enablerepo=remi,remi-php70 \
httpd php php-pdo php-mysqlnd \
php-xml php-mbstring php-mcrypt \
php-opcache php-pecl-swoole2 unzip \
&& yum clean all \
&& rm -rf /var/cache/yum \
&& curl -o /usr/bin/composer \
https://getcomposer.org/download/1.10.20/composer.phar \
&& chmod a+x /usr/bin/composer
#port and entry
EXPOSE 80
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
其中,大部分是 Laravel 使用的功能,只有 php-pecl-swoole2 為 PHP 增加 Swoole 功能,php-pecl-inotify 則是為了偵測檔案變動重新載入程式。
Google 和 Github 上,都是 swooletw/laravel-swoole 的關注度高很多,那就先測試 swooletw/laravel-swoole。
composer update 時發生錯誤,處理方式
docker exec -it --user 1000:1000 docker_web_1 bash |
bash-4.2$ php -r "echo ini_get('memory_limit').PHP_EOL;" 128M bash-4.2$ php -d memory_limit=-1 /usr/bin/composer update |
然後依據說明,在命令列下指令啟動 swoole server
php artisan swoole:http {start|stop|restart|reload|infos}
然後用瀏覽器瀏覽網頁,但是一直出錯。測試結果都是不成功,在讀取網頁時,一直出現下列錯誤
PHP Fatal error: Call to undefined method Symfony\Component\HttpFoundation\ResponseHeaderBag::allPreserveCaseWithoutCookies() in /var/www/html/swoole_tst/vendor/swooletw/laravel-swoole/src/Server/Response.php on line 73
根據 google 到的資訊
allPreserveCaseWithoutCookies() is available after Symfony 3.4, what's your Laravel version?
Before Laravel 5.3, symfony/http-foundation is too old to use function allPreserveCaseWithoutCookies(). I'll try to make it compatible in the next release.
換了較舊版本的 laravel-swoole,或換較新版本的 Laravel,都不能成功,最後放棄。
第一次的測試碰到挫折,那就改為使用 hhxsv5/laravel-s 來測試。相對而言,laravel-s 較為麻煩,耐心的安裝設定後,依照說明下指令啟動 laravels,看到執行的畫面了,稍微了解運作方式之後,也可以在瀏覽器看到結果了。
bash-4.2$ php bin/laravels start basePath: /var/www/html/swoole_tst/web-src VENDORDIR: /var/www/html/swoole_tst/web-src/../vendor _ _ _____ | | | |/ ____| | | __ _ _ __ __ ___ _____| | (___ | | / _` | '__/ _` \ \ / / _ \ |\___ \ | |___| (_| | | | (_| |\ V / __/ |____) | |______\__,_|_| \__,_| \_/ \___|_|_____/
Speed up your Laravel/Lumen >>> Components +---------------------------+--------------+ | Component | Version | +---------------------------+--------------+ | PHP | 7.0.33 | | Swoole | 2.2.0 | | LaravelS | 3.6.4 | | Laravel Framework [local] | 5.1.46 (LTS) | +---------------------------+--------------+ >>> Protocols +-----------+--------+-------------------+----------------+ | Protocol | Status | Handler | Listen At | +-----------+--------+-------------------+----------------+ | Main HTTP | On | Laravel Framework | 127.0.0.1:5200 | +-----------+--------+-------------------+----------------+ >>> Feedback: https://github.com/hhxsv5/laravel-s [2021-03-03 07:41:57] [TRACE] Swoole is running, press Ctrl+C to quit. |
{ "name": "laravel/laravel", "description": "The Laravel Framework.", "keywords": ["framework", "laravel"], "license": "MIT", "type": "project", "require": { "php": ">=5.5.9", "laravel/framework": "5.1.*", "hhxsv5/laravel-s": "3.6.*" }, "require-dev": { "fzaninotto/faker": "~1.4", "mockery/mockery": "0.9.*", "phpunit/phpunit": "~4.0", "phpspec/phpspec": "~2.1" }, "autoload": { "classmap": [ "database" ], "psr-4": { "App\\": "app/" } }, "autoload-dev": { "classmap": [ "tests/TestCase.php" ] }, "scripts": { "post-root-package-install": [ "php -r \"copy('.env.example', '.env');\"" ], "post-create-project-cmd": [ "php artisan key:generate" ], "post-install-cmd": [ "Illuminate\\Foundation\\ComposerScripts::postInstall", "php artisan optimize" ], "post-update-cmd": [ "Illuminate\\Foundation\\ComposerScripts::postUpdate", "php artisan optimize" ] }, "config": { "preferred-install": "dist", "vendor-dir": "../vendor" } } |
在 laravel-s 的 git 專案網頁中,相關的說明蠻細的,一下子吸收不了那麼多,其中有一段是使用 httpd 的 reverse-proxy 來提供服務的說明,就照著設,內容大致如下,可以正常運作,但不盡完美,等後面測試累積較多經驗後,再來整理說明。
ProxyRequests Off <Proxy *> Order allow,deny Allow from all </Proxy> # ProxyVia On ProxyPass /swoole-web http://127.0.0.1:5200 ProxyPassReverse /swoole-web http://127.0.0.1:5200 |
後續報告,經過 2 個多星期的奮鬥之後,想法有一些改變,可以在進入 kernel 的服務之前,預做一些處理,程式要改動部份就很少了。