需求:用户小程序下单成功管理员后台通过websocket通知业务员有新订单的提示,但是小程序都是要开启https才能使用的,需要在宝塔配置一下,配置如下

location ~* (runtime|application)/{
return 403;
}
location / {
if (!-e $request_filename){
rewrite ^(.*)$ /index.php?s=$1 last; break;
}
}
location /wss
{
proxy_pass http://127.0.0.1:2346;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
rewrite /wss/(.*) /$1 break;
proxy_redirect off;
}
我的配置文件如下,仅供参考map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# 这里的backend可以改成自己需要的名称,我自己用的是wss。
upstream wss {
# 这里的localhost是映射本地服务器,也可以是外网ip,2345是我ws开启的端口。
server localhost:2346;
}
server
{
listen 80 default_server;
listen 443 ssl http2 default_server;
server_name xxxxx.cn www.laiyashiji.cn;
index index.php index.html index.htm default.php default.htm default.html;
root /www/wwwroot/xxxxx.cn/hotel/public;
#SSL-START SSL相关配置,请勿删除或修改下一行带注释的404规则
#error_page 404/404.html;
ssl_certificate /www/server/panel/vhost/cert/xxxxx.cn/fullchain.pem;
ssl_certificate_key /www/server/panel/vhost/cert/xxxxx.cn/privkey.pem;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES828:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
add_header Strict-Transport-Security "max-age=31536000";
error_page 497 https://$host$request_uri;
#SSL-END
#ERROR-PAGE-START 错误页配置,可以注释、删除或修改
#error_page 404 /404.html;
#error_page 502 /502.html;
#ERROR-PAGE-END
#PHP-INFO-START PHP引用配置,可以注释或修改
include enable-php-74.conf;
#PHP-INFO-END
#REWRITE-START URL重写规则引用,修改后将导致面板设置的伪静态规则失效
include /www/server/panel/vhost/rewrite/xxxxx.cn.conf;
#REWRITE-END
#禁止访问的文件或目录
location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md)
{
return 404;
}
#一键申请SSL证书验证目录相关设置
location ~ \.well-known{
allow all;
}
#禁止在证书验证目录放入敏感文件
if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) {
return 403;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
error_log /dev/null;
access_log /dev/null;
}
location ~ .*\.(js|css)?$
{
expires 12h;
error_log /dev/null;
access_log /dev/null;
}
access_log /www/wwwlogs/xxxxx.cn.log;
error_log /www/wwwlogs/xxxxx.cn.error.log;
}

参考链接地址:https://cloud.tencent.com/developer/article/2013269
参考链接地址:https://www.cnblogs.com/chengwens/p/17721401.html
代理开启成功后需要配置TP框架Workerman实现websocket前后端通信了,
第一步创建一个worker文件目录和Worker.php文件


代码
<?php
namespace app\worker\controller;
use think\worker\Server;
use Workerman\Lib\Timer;
class Worker extends Server
{
protected $socket = 'websocket://127.0.0.1:2346';
protected $processes = 1;//进程数
protected $worker;
protected $HEARTBEAT_TIME = '60';//心跳时间,后端主动关闭客户端
public function __construct()
{
parent::__construct();
$this->worker->uidConnections = array(); //用户链接池 存储映射
}
/**
* 接收消息
* @param $connection
* @param $data
*/
public function onMessage($connection, $data)
{
//客户端与后端消息链接唯一标识
$uid = $connection->uid;
if($uid) {
$data=json_decode($data,true);
$message=['code'=>0,'msg'=>'你还活着','type'=>0,'data'=>[]];
if(!$data){
return true;
}
//区分各种业务处理
$method = $data['method'];
$is_push=0;//是否主动推送消息
switch ($method) {
//创建聊天室
case 'add_chat':
$is_push=1;//开启推送
$chat_id=1111;//你的聊天室id 返回给前端
$message=['code'=>0,'msg'=>'创建成功','type'=>-1,'data'=>$chat_id];
break;
//发送消息
case 'send':
$is_push=1;//开启推送
$message='你处理的消息信息';
//如果对方在线 向对方发送一条消息
$this->sendMessageByUid($data['user_id'],$message);
$message2='聊天消息列表';
//对方在线 更新对方消息接收列表(没做分页处理,分页后台发送单条信息前端使用push)
$this->sendMessageByUid($data['user_id'],$message2);
break;
//客户端主动来取消息列表
case 'list':
$is_push=1;//开启推送
$message='聊天消息列表';
break;
//客户端主动取聊天室内容
case 'chat_list':
$is_push=1;//开启推送
$post=[
'user_id'=>$uid,
'chat_id'=>$data['chat_id'],//聊天室id
'page'=>$data['page'],//分页数
];
$message=ChatList::getList($post);
break;
}
//向自己推送消息
if($is_push){
$this->sendMessageByUid($uid,$message);
}
}else{//查询不到用户信息,关闭此连接
$this->onClose($connection);
}
}
// 向所有验证的用户推送数据
function broadcast($message)
{
foreach($this->worker->uidConnections as $connection)
{
$connection->send($message);
}
}
// 针对uid推送数据
function sendMessageByUid($uid, $message)
{
if(isset($this->worker->uidConnections[$uid]))
{
$connection = $this->worker->uidConnections[$uid];
$connection->send(json_encode($message,true));
}
}
/**
* 当连接建立时触发的回调函数
* @param $connection
*/
public function onConnect($connection)
{
$connection->onWebSocketConnect = function($connection , $http_header)
{
// 可以在这里判断连接来源是否合法,不合法就关掉连接
// $_SERVER['HTTP_ORIGIN']标识来自哪个站点的页面发起的websocket连接
// $arr_request=[
// 'https://laiyashiji.cn',
// '域名2',
// ];
// //判断是否合法连接
// if(in_array( http_header['Host'],$arr_request) !=true)
// {
// $connection->close();
// }
$connection->send('received: ' . $http_header);
// 存客户端与websocket的映射,唯一连接标识(!!!关键)
if(!isset($connection->uid))
{
// $connection->uid = $_SERVER['HTTP_TOKEN'];
// $this->worker->uidConnections[$connection->uid]=$connection;
// return;
}
};
}
/**
* 当连接断开时触发的回调函数
* @param $connection
*/
public function onClose($connection)
{
// //代表用户下线,清除用户信息
if(isset($connection->uid))
{
// 连接断开时删除映射
unset($this->worker->uidConnections[$connection->uid]);
}
}
/**
* 当客户端的连接上发生错误时触发
* @param $connection
* @param $code
* @param $msg
*/
public function onError($connection, $code, $msg)
{
echo "error $code $msg\n";
}
/**
* 每个进程启动
* @param $worker
*/
public function onWorkerStart($worker)
{
//每10秒检查一下客户端是否还连着服务端。超时未相应也会主动关闭与客户端的连接
Timer::add(10, function()use($worker){
$time_now = time();
foreach($worker->connections as $connection) {
// 有可能该connection还没收到过消息,则lastMessageTime设置为当前时间
if (empty($connection->lastMessageTime)) {
$connection->lastMessageTime = $time_now;
continue;
}
$diff_time = $time_now - $connection->lastMessageTime;
$msg = '距离上次通话已经过去'.$diff_time.'秒';
$message=['code'=>0,'msg'=>$msg,'type'=>0,'data'=>[]];
$connection->send(json_encode($message,true));
// 上次通讯时间间隔大于心跳间隔,则认为客户端已经下线,关闭连接
if ($time_now - $connection->lastMessageTime > $this->HEARTBEAT_TIME) {
$connection->close();
}
}
});
}
}
第二步在项目根目录的public下创建workerman的启动文件server.php
<?php
define('APP_PATH', __DIR__ . '/../application/');
define('BIND_MODULE','worker/Worker');
// 加载框架引导文件
require __DIR__ . '/../thinkphp/start.php';
第三步安装workerman,通过
composer require workerman/workerman 安装,最好,最好,最好安装workerman 4.0以上的版本,本人一开始用3.5.35版本用同样的代码和配置和反代理就是运行不起来,但是又不报错,想了半天想起以前在本地搭建过一个workerman的,然后看了一下版本,抱着试一下的心态把workerman的库文件复制到项目中取,结果就运行起来了
{
"require": {
"workerman/workerman": "^4.0"
}
}

第四步需要启动workerman,还记得刚刚创建的server.php文件吗,在服务器终端运行 php server.php start 这里没有加-d,在调试阶段就不要加-d了,如果觉得代码没啥问题了就使用 php server.php start -d 运行

如果在运行中出现端口被占用可以用kill -9 端口号 停掉,如
kill -9 25529
查看端口占用情况,如果遇到启动成功但是查询不到端口建议换一下workerman版本试试
netstat -anp | grep 2346
查看所有服务,可以查看server.php服务有没有启用成功ps aux
第五步前端连接websocket

连接成功
