1、先在nginx里配置
location /wss
{
proxy_pass http://127.0.0.1:8282;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
#這部分是利用http頭透傳真實客戶端ip
proxy_set_header X-Real-IP $remote_addr;
}
2、workerman從nginx設置的header里讀取客戶端ip
$connection->onWebSocketConnect = function($connection){
/**
* connection對象本沒有realIP屬性,這里給connection對象動態(tài)添加個realIP屬性
* 記住php對象是可以動態(tài)添加屬性的,你也可以用自己喜歡的屬性名
*/
$connection->realIP = $_SERVER['HTTP_X_REAL_IP'];
};
PHP在CLI模式下能有 $_SERVER['HTTP_X_REAL_IP'] 這個環(huán)境變量么?
這個坑誰來填?
這種錯誤會誤導很多開發(fā)者!??!
簡單來說:Workerman目前在下面情況下,是不能獲取到真實客戶端IP的
1、先以PHP CLI模式啟動【websocket】服務端協(xié)議 websocket://127.0.0.1:8443
2、nginx添加http代理【https://wss.xxx.com】,轉到【http://127.0.0.1:8443】
3、websocket服務端通過 $_SERVER['HTTP_X_REAL_IP'] 系統(tǒng)變量,是不能獲取到任何IP信息的
4、通過實踐會直接報錯,找不到 HTTP_X_REAL_IP
因為 $_SERVER['HTTP_X_REAL_IP'] 只能通過非命令行方式獲?。?/p>
說明:以下是 代理轉發(fā)場景下,需要獲取客戶端真實IP的解決方案
1、項目轉用 GatewayWorker 框架
2、在 onWebSocketConnect 事件中,重要的事情說3遍
2、在 onWebSocketConnect 事件中,重要的事情說3遍
2、在 onWebSocketConnect 事件中,重要的事情說3遍
3、因為onConnect 事件屬于TCP握手完成事件,只能通過$_SERVER['REMOTE_ADDR'] 獲取IP,不能獲取到代理場景下客戶真實IP
4、```php
public static function onWebSocketConnect($client_id, $data)
{
var_export($data);
echo $data['HTTP_X_REAL_IP']."\n";
}
## 千萬別相信教程里使用 $_SERVER['HTTP_X_REAL_IP'],CNM
教程哪里誤導開發(fā)者了呢? 我認為是你理解的有問題,列幾點自己的認識:
1、既然你提到了CLI模式和非CLI模式,這個本身就是錯誤的認識,workerman只能工作在CLI模式,什么時候有了非CLI模式一說呢?
2、workerman和gatewayworker本身就不是一個東西:
workerman一個是底層的socket框架,gatewayworker則是基于workerman針對特定長連接應用場景開發(fā)出來的應用框架;
3、對于websocket協(xié)議,其握手階段是基于http協(xié)議實現(xiàn)的,所以在onWebSocketConnect($connection, $http_header)回調中我們可以直接或間接的解析到$_SERVER變量,上面說了:workerman和gatewayworker本身就不是一個東西,workerman對于$_SERVER變量可以直接拿到;但是gatewayworker的Gateway::onWebSocketConnect() 和 Events::onWebSocketConnect() 回調是有些許差別的,前者也可以直接拿到$_SERVER變量【手冊里寫的很清楚在start_gateway.php里的這個回調中來獲取nginx設置的http頭,所以哪里誤導開發(fā)者了呢?】,而后者雖然直接拿不到該變量里的某些字段,但是我們可以從$http_header這個變量里頭隨時拿到你想要的東西【因為它是Gateway進程轉發(fā)來的】;
文檔中這一章節(jié)并沒有錯誤,不管是workerman的onWebSocketConnect 還是gatewayWorker中start_gateway.php里的onWebSocketConnect 都可以使用 $_SERVER['HTTP_X_REAL_IP ']
來獲得nginx轉發(fā)來的ip。因為workerman包括gatewayWorker在websocket握手的時候會給$_SERVER['HTTP_X_REAL_IP ']
賦值,所以可以拿到這個值。
workerman文檔已經(jīng)寫了很多年了,N多開發(fā)者使用這個方法獲得nginx代理后的客戶端真實IP,如果這里有問題幾年前就被發(fā)現(xiàn)了,不會遺留到今天。
你本身就沒分清楚 workerman 和 gatewayworker 吧?一會 workerman,一會又 gatewayworker,將 workerman 的手冊當成 gatewayworker 的手冊了。
另外,workerman 本身就以 cli 模式運行,cli 是 sapi 的一種,sapi 還包括 fastcgi、cgi 等。不知道你指的非命令行又是什么?
$_SERVER 是 PHP 根據(jù) nginx 的請求報文設置的。如果你用的是 gatewayworker,你可以簡單地將 gatewayworker 理解成另一個 nginx,它將 php 接收到的請求報文再轉發(fā)給其它 php 進程(也就是 businessworker),在這個過程中,businessworker 并沒有將將請求內容設置到 $_SERVER 中,當然如果你自己有能力可以修改 gatewayworker 源碼的 BusinessWorker.php,查找以下方法:
public function onGatewayMessage($connection, $data)
$_SERVER 就是在這里設置的。
手冊并沒有寫錯。