常見問題
如何處理靜態資源
Apache URl rewrite
<IfModule mod_rewrite.c>
Options +FollowSymlinks
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
# RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L] fcgi下無效
RewriteRule ^(.*)$ http://127.0.0.1:9501/$1 [QSA,P,L]
# 請開啟 proxy_mod proxy_http_mod request_mod
</IfModule>
Nginx URl rewrite
server {
root /data/wwwroot/;
server_name local.swoole.com;
location / {
proxy_http_version 1.1;
proxy_set_header Connection "keep-alive";
proxy_set_header X-Real-IP $remote_addr;
if (!-f $request_filename) {
proxy_pass http://127.0.0.1:9501;
}
}
}
Swoole 靜態文件處理器
詳細請可查看 配置文件 章節
修改配置文件的 dev.php
或者 produce.php
,實現 Swoole
對靜態文件進行處理。
<?php
return [
// ...... 這里省略
'MAIN_SERVER' => [
// ...... 這里省略
'SETTING' => [
// ...... 這里省略
# 設置處理 Swoole 靜態文件
'document_root' => EASYSWOOLE_ROOT . '/Static/',
'enable_static_handler' => true,
],
// ...... 這里省略
],
// ...... 這里省略
];
上述配置是假設你的項目根目錄有個 Static 目錄是用來放置靜態文件的。具體的使用可查看 https://wiki.swoole.com/#/http_server?id=document_root
關于跨域處理
在框架的初始化事件 initialize 事件 中進行注冊。
注冊示例代碼如下:
public static function initialize()
{
date_default_timezone_set('Asia/Shanghai');
// onRequest v3.4.x+
\EasySwoole\Component\Di::getInstance()->set(\EasySwoole\EasySwoole\SysConst::HTTP_GLOBAL_ON_REQUEST, function (\EasySwoole\Http\Request $request, \EasySwoole\Http\Response $response) {
$origin = $request->getHeader('origin')[0] ?? '*';
$response->withHeader('Access-Control-Allow-Origin', $origin);
$response->withHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
$response->withHeader('Access-Control-Allow-Credentials', 'true');
$response->withHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With, token');
if ($request->getMethod() === 'OPTIONS') {
$response->withStatus(\EasySwoole\Http\Message\Status::CODE_OK);
return false;
}
return true;
});
}
EasySwoole 3.4.x
版本之前:可在項目根目錄的 EasySwooleEvent.php
中看到 onRequest
及 afterRequest
方法.
如何獲取 $HTTP_RAW_POST_DATA
$content = $this->request()->getBody()->__toString();
$raw_array = json_decode($content, true);
如何獲取客戶端 IP
舉例,如何在控制器中獲取客戶端 IP
// 真實地址
// 獲取連接的文件描述符
$fd = $this->request()->getSwooleRequest()->fd;
$ip = \EasySwoole\EasySwoole\ServerManager::getInstance()->getSwooleServer()->connection_info($fd);
var_dump($ip);
// header 地址,例如經過 nginx proxy 后
$ip2 = $this->request()->getHeaders();
var_dump($ip2);
HTTP 狀態碼總為500
自 swoole 1.10.x 和 2.1.x 版本起,執行 http server
回調中,若未執行 response->end()
,則全部返回 500
狀態碼
如何 setCookie
調用 response
對象的 setCookie
方法即可設置 cookie
。setCookie
方法和原生 setcookie
用法一致。
$this->response()->setCookie('name', 'value');
更多操作可看 Response 對象
如何自定義 App 命名空間對應目錄
只需要修改項目根目錄的 composer.json
的自動加載的 App
命名空間對應的目錄即可,然后執行 composer dumpautolaod -o
注冊就行。
{
// ... 這里省略
"autoload": {
"psr-4": {
"App\\": "Application/"
}
}
}
如何啟用 Https
通常建議使用 Nginx
或者 Lb
來配置證書,將 https
請求解析為 http
反代到 swoole
如果你僅是測試使用,可以在配置文件 (dev.php
或者 produce.php
) 中添加和修改以下配置來啟用https。
<?php
return [
// ...... 這里省略
'MAIN_SERVER' => [
// ...... 這里省略
'SOCK_TYPE' => SWOOLE_TCP | SWOOLE_SSL, // 默認是 SWOOLE_TCP
'SETTING' => [
'ssl_cert_file' => '證書路徑,僅支持.pem格式',
'ssl_key_file' => '私鑰路徑',
]
// ...... 這里省略
],
// ...... 這里省略
];
詳細請可查看 配置文件 章節
DNS Lookup resolve timeout 錯誤
該錯誤一般存在于 http
客戶端并發調用時產生,原因是 dns
效率慢,導致多線程獲取 dns
時超時,包括不限于以下場景:
- mysql host 設置為域名形式,并且設置最小連接高于 2(很難看到,一般是 10 才會偶爾報錯)
- HTTPClient 多個協程同時并發
- csp 并發編程 等
解決方法為:
在并發之前,預先使用 Swoole\Coroutine::gethostbyname('www.baidu.com')
; 去查詢一次dns ip
,swoole
底層才會自動緩存該 ip
。
例如:
Swoole\Coroutine::gethostbyname('www.baidu.com');
for ($j = 0; $j < 100; $j++) {
go(function () use ($j) {
for ($i = 0; $i < 1000; $i++) {
$client = new Swoole\Coroutine\Http\Client('www.baidu.com', 443, true);
$client->get('/');
if (empty($client->errMsg)) {
//var_dump($client->getBody());
} else {
var_dump($client->errMsg);
}
}
});
}
CURL 發送 POST請求 EasySwoole 服務器端超時
- 出現原因:
CURL
在發送較大的POST
請求(例如: 上傳文件)時會先發一個100-continue
的請求,如果收到服務器的回應才會發送實際的POST
數據。而swoole_http_server
(即EasySwoole
的Http
主服務) 不支持100-continue
,就會導致CURL
請求超時。 - 解決方法:
方法1:關閉
CURL
的100-continue
,在CURL
的Header
中配置關閉100-continue
選項。
示例代碼(php):
<?php
// 創建一個新cURL資源
$ch = curl_init();
// 設置URL和相應的選項
curl_setopt($ch, CURLOPT_URL, "http://127.0.0.1:9501");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_POST, 1); // 設置為POST方式
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:')); // 關閉 `CURL` 的 `100-continue`
curl_setopt($ch, CURLOPT_POSTFIELDS, array('test' => str_repeat('a', 800000)));// POST 數據
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
方法2:使用
Nginx
做前端代理,由Nginx
處理100-Continue
(針對無法關閉100-continue
時)
http 服務中公共函數如何引入
很多開發小伙伴在開發過程中可能遇到疑惑,在 EasySwoole
怎么像 ThinkPHP
框架那樣引入自定義的公共函數,接下來簡單說明下引入方法,這邊推薦借助 composer
的自動加載機制 (Files
)實現。
修改項目根目錄的 composer.json
文件的 autoload.files
選項,示例如下:
{
// ... 這里省略
"autoload": {
// ... 這里省略
"files": ["App/Common/functions.php"]
}
}
然后新建文件 App\Common\functions.php
,在 functions.php
中編寫自己的自定義函數,再在項目根目錄執行 composer dumpautoload
完成自動加載,就可以在框架的任意位置進行調用函數了。
示例如下:
<?php
// functions.php
if (!function_exists('helloEasySwoole')) {
function helloEasySwoole()
{
echo 'Hello EasySwoole!';
}
}
// ... 更多自定義函數
調用示例:
<?php
namespace App\HttpController;
use EasySwoole\Http\AbstractInterface\Controller;
class Index extends Controller
{
function index()
{
\helloEasySwoole();
}
}
自定義函數都可以放在這個文件中。