workerman PHP CLI模式 获得客户端IP问题

qplchen

官方文档里【透过nginx/apache代理如何获取客户端真实ip】这一章


我们先看文档

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对象动态添加个realIP属性
        * 记住php对象是可以动态添加属性的,你也可以用自己喜欢的属性名
        */
       $connection->realIP = $_SERVER['HTTP_X_REAL_IP'];
   };

好的,坑来了?


PHP在CLI模式下能有 $_SERVER['HTTP_X_REAL_IP'] 这个环境变量么?

这个坑谁来填?

4426 5 0
5个回答

qplchen

这种错误会误导很多开发者!!!

简单来说:Workerman目前在下面情况下,是不能获取到真实客户端IP的

1、先以PHP CLI模式启动【websocket】服务端协议 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'] 系统变量,是不能获取到任何IP信息的
4、通过实践会直接报错,找不到 HTTP_X_REAL_IP

因为 $_SERVER['HTTP_X_REAL_IP'] 只能通过非命令行方式获取!

  • 暂无评论
qplchen

说明:以下是 代理转发场景下,需要获取客户端真实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
  • qplchen 2020-08-30

    $data['server']['HTTP_X_REAL_IP']

  • 朕震惊了 2020-08-30

    看到了“CNM”三个刺眼的字母,顿时觉得题主不仅能力“高”得出奇,素质更是令人震惊。结果最后证明文档并无错误,不知题主脸红不红,疼不疼,声音响不响。

blogdaren

教程哪里误导开发者了呢? 我认为是你理解的有问题,列几点自己的认识:
1、既然你提到了CLI模式和非CLI模式,这个本身就是错误的认识,workerman只能工作在CLI模式,什么时候有了非CLI模式一说呢?
2、workerman和gatewayworker本身就不是一个东西:
workerman一个是底层的socket框架,gatewayworker则是基于workerman针对特定长连接应用场景开发出来的应用框架;
3、对于websocket协议,其握手阶段是基于http协议实现的,所以在onWebSocketConnect($connection, $http_header)回调中我们可以直接或间接的解析到$_SERVER变量,上面说了:workerman和gatewayworker本身就不是一个东西,workerman对于$_SERVER变量可以直接拿到;但是gatewayworker的Gateway::onWebSocketConnect() Events::onWebSocketConnect() 回调是有些许差别的,前者也可以直接拿到$_SERVER变量【手册里写的很清楚在start_gateway.php里的这个回调中来获取nginx设置的http头,所以哪里误导开发者了呢?】,而后者虽然直接拿不到该变量里的某些字段,但是我们可以从$http_header这个变量里头随时拿到你想要的东西【因为它是Gateway进程转发来的】;

  • 暂无评论
walkor

文档中这一章节并没有错误,不管是workerman的onWebSocketConnect 还是gatewayWorker中start_gateway.php里的onWebSocketConnect 都可以使用 $_SERVER['HTTP_X_REAL_IP ']来获得nginx转发来的ip。因为workerman包括gatewayWorker在websocket握手的时候会给$_SERVER['HTTP_X_REAL_IP ']赋值,所以可以拿到这个值。

workerman文档已经写了很多年了,N多开发者使用这个方法获得nginx代理后的客户端真实IP,如果这里有问题几年前就被发现了,不会遗留到今天。

  • 暂无评论
JustForFun

你本身就没分清楚 workerman 和 gatewayworker 吧?一会 workerman,一会又 gatewayworker,将 workerman 的手册当成 gatewayworker 的手册了。

另外,workerman 本身就以 cli 模式运行,cli 是 sapi 的一种,sapi 还包括 fastcgi、cgi 等。不知道你指的非命令行又是什么?

$_SERVER 是 PHP 根据 nginx 的请求报文设置的。如果你用的是 gatewayworker,你可以简单地将 gatewayworker 理解成另一个 nginx,它将 php 接收到的请求报文再转发给其它 php 进程(也就是 businessworker),在这个过程中,businessworker 并没有将将请求内容设置到 $_SERVER 中,当然如果你自己有能力可以修改 gatewayworker 源码的 BusinessWorker.php,查找以下方法:

public function onGatewayMessage($connection, $data)

$_SERVER 就是在这里设置的。

手册并没有写错。

  • 暂无评论
年代过于久远,无法发表回答
🔝