方式一 :通过 swoole 的request 对象获取客户端IP
场景: 客户端直接远程使用IP+端口访问webscoket服务。
关键核心代码如下:
$server->on('message', function($server, $frame) { $res = $server->getClientInfo($frame->fd); $ip = $res[‘remote_ip’]; }
$res 具体数据格式:
array(11) { ["websocket_status"]=>int(3) ["server_port"]=>int(9502) ["server_fd"]=>int(9) ["socket_fd"]=>int(23) ["socket_type"]=>int(1) ["remote_port"]=>int(50758) ["remote_ip"]=>string(9) "127.0.0.1" ["reactor_id"]=>int(3) ["connect_time"]=>int(1565747287) ["last_time"]=>int(1565747287) ["close_errno"]=>int(0) }
提示: 远程开放socket端口不安全,不建议此方式
方式二: 通过 nginx 反向代理到 webscoket 获取客户端IP
首先配置nginx反向代理,配置关键代码如下:
location /websocket { proxy_redirect off; proxy_pass #websocket proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-For $remote_addr; #配置IP }
假设我们这里配置的域名是:www.lakeui.com
场景: 客户端通过域名访问webscoket服务。
例如: ws://www.lakeui.com/webscoket
由于所有客户端都是通过nginx代理到websocket,所以websocket再通过方法一获取的ip都是127.0.0.1 ,这里的关键就在nginx的反向代理配置:
proxy_set_header X-Forwarded-For $remote_addr;
表示将客户端IP通过头信息传递给websocket,webscoket可以通过头信息获取客户端IP,关键核心代码如下:
$server->on('open', function($server, $req) { $ip = $req->header['x-forwarded-for']; });
本以为可以结束了,可实际swoole只有在open回调方法中才能获取request对象,可业务一般在message回调中处理,ip又如何获取和传递了?
查询了swoole相关文档,没有找到相应的获取方法于是只有想办法将ip传递。关键代码如下:
$ips = []; //定义一个全局ip存放数组 $server->on('open', function($server, $req) { global $ips; $ips[$req->fd] = $req->header['x-forwarded-for']; //将客户端标示与IP关联存入全局数组 }); $server->on('message', function($server, $frame) { global $ips; $ip = $ips[$frame->fd]; //获取客户端IP }); //注意一定要释放ip,否则会导致内存爆掉 $server->on('close', function($server, $fd) { global $ips; unset($ips[$fd]); //客户端断开时清除ip关联 });
以上方式是目前我发现的解决办法,如果各位大神又更好的解决方法,可以留言或者联系我,一起共同学习!