微信小程序 - websocket wss

准备工作:
1、GatewayWorker 监听 8585 端口(websocket协议)
2、已经申请了ssl证书[阿里云免费证书], 放在了/server/httpd/cert/ 下
3、利用apache转发443端口至指定端口
4、httpd-ssl.conf 已加载
5、openssl 已安装
6、小程序已设置 socket 合法域名 wss://www.xxx.com

如果处于开发阶段,关闭小程序的相关校验, 微信web开发者工具 -> 设置 -> 项目设置 -> 勾选 不校验安全域名、web-view 域名、TLS 版本以及 HTTPS 证书

启用 proxy_wstunnel_module 模块

1
2
3
#httpd.conf
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so

配置SSL及代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#extra/httpd-ssl.conf
DocumentRoot "/www/socket"
ServerName localhost
ErrorLog "/log/httpd/socket-error.log"
TransferLog "/log/httpd/socket-access.log"

# Proxy Config
SSLProxyEngine on
#监听的路径和转发的路径,需要输入https://和最后面的/
ProxyRequests Off
ProxyPass /wss ws://0.0.0.0:8585
ProxyPassReverse /wss ws://0.0.0.0:8585
#ProxyPass / https://www.baidu.com
#ProxyPassReverse / https://www.baidu.com

# 添加 SSL 协议支持协议,去掉不安全的协议
SSLProtocol all -SSLv2 -SSLv3
# 修改加密套件如下
SSLCipherSuite HIGH:!RC4:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!EXP:+MEDIUM
SSLHonorCipherOrder on
# 证书公钥配置
SSLCertificateFile cert/public.pem
# 证书私钥配置
SSLCertificateKeyFile cert/2222222222222.key
# 证书链配置,如果该属性开头有 '#'字符,请删除掉
SSLCertificateChainFile cert/chain.pem

配置 GatewayWorker,并启动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# socket.php
<?php
use Workerman\Worker;
use Workerman\Lib\Timer;
use GatewayWorker\Register;
use GatewayWorker\Gateway;
use GatewayWorker\BusinessWorker;

if (strpos(strtolower(PHP_OS), 'win') === 0) {
exit("Not support windows\n");
}

if (!extension_loaded('pcntl')) {
exit("Please install pcntl extension. See http://doc3.workerman.net/appendices/install-extension.html\n");
}

if (!extension_loaded('posix')) {
exit("Please install posix extension. See http://doc3.workerman.net/appendices/install-extension.html\n");
}

$config = [
'path' => __DIR__ . '/GatewayWorker/',
'register_address' => '127.0.0.1:1251',
'ws_gateway_socket' => 'websocket://0.0.0.0:8585',
'ws_gateway_name' => 'ws_gateway',
'ws_gateway_count' => 4,
'gateway_lan_ip' => '127.0.0.1',
'ws_gateway_start_port' => 6000,
'gateway_ping_interval' => 2500,
'gateway_ping_not_response_limit' => 2,
'gateway_ping_data' => '',
'businessworker_name' => 'businessworker',
'businessworker_count' => 4,
'businessworker_event_handler' => 'SocketEvents',
'log_file' => __DIR__ . '/multiprotocol.log'
];
require_once $config['path'] . 'vendor/autoload.php';

// register服务
$register = new Register('text://' . $config['register_address']);

$context = [];
// 若是h5 websocket,wss可以指定端口,就不需要配置apache代理,只需要配置$context即可
// $context = array(
// 'ssl' => array(
// 'local_cert' => '/server/httpd/cert/2222222222222.pem',
// 'local_pk' => '/server/httpd/cert/2222222222222.key',
// 'verify_peer' => false
// )
// );
// gateway进程
$gateway = new Gateway($config['ws_gateway_socket'], $context);
// 开启SSL,websocket+SSL 即wss
!empty($context) && $gateway->transport = 'ssl';
$gateway->name = $config['ws_gateway_name'];
$gateway->count = $config['ws_gateway_count'];
$gateway->lanIp = $config['gateway_lan_ip'];
$gateway->startPort = $config['ws_gateway_start_port'];
$gateway->registerAddress = $config['register_address'];
$gateway->pingInterval = $config['gateway_ping_interval'];
$gateway->pingNotResponseLimit = $config['gateway_ping_not_response_limit'];
$gateway->pingData = $config['gateway_ping_data'];

// bussinessWorker 进程
$worker = new BusinessWorker();
$worker->name = $config['businessworker_name'];
$worker->count = $config['businessworker_count'];
$worker->registerAddress = $config['register_address'];
$worker->eventHandler = $config['businessworker_event_handler'];

// 监控文件更新并自动reload[只有在debug模式启动后才有效,daemon模式不生效]
global $lastMtime;
$lastMtime = time();
$worker = new Worker();
$worker->name = 'FileMonitor';
$worker->reloadable = false;
$worker->onWorkerStart = function() {
$monitorDir = __DIR__;
if (!Worker::$daemonize) {
Timer::add(1, 'check_files_change', [$monitorDir]);
}
};

// 自定义workerman日志路径
Worker::$logFile = $config['log_file'];

Worker::runAll();

function check_files_change($monitorDir)
{
global $lastMtime;
$dirIterator = new RecursiveDirectoryIterator($monitorDir);
$iterator = new RecursiveIteratorIterator($dirIterator);
foreach ($iterator as $file) {
if(pathinfo($file, PATHINFO_EXTENSION) != 'php') {
continue;
}

if($lastMtime < $file->getMTime())
{
echo "{$file} update and reload\n";
// send SIGUSR1 signal to master process for reload
posix_kill(posix_getppid(), SIGUSR1);
$lastMtime = $file->getMTime();
break;
}
}
}
1
php socket.php start

h5 websocket

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title></title>
</head>
<body>
<script>
// 普通方式
// var ws = new WebSocket('wss://www.xxx.com:8585');
// 使用代理的方式
var ws = new WebSocket('wss://www.xxx.com/wss');
ws.onopen = function() {
ws.send('this is h5');
};
ws.onmessage = function(e) {
console.log(e.data);
};
</script>
</body>
</html>

小程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
var that = this;
wx.connectSocket({
url: "wss://www.xxx.com/wss"
});

wx.onSocketOpen(function(res) {
console.log('WebSocket连接已打开!');
};
wx.sendSocketMessage({
data: 'this is wxapp'
});

wx.onSocketMessage(function (data) {
console.log('收到服务器内容:' + res.data);
});

wx.onSocketError(function () {
console.log('WebSocket连接打开失败,请检查!');
});
}
0%