在以前的文章中,我们介绍了HTTP通讯,这种通讯有一个缺点,如果我想从直接从服务器发消息给客户端,需要客户端先发起HTTP请求后服务器才能返回数据,且后续服务器想发送数据给客户端都需要客户端先发起请求,但这种方案在一些特殊场景应用的时候非常消耗资源,比如聊天室,如果使用HTTP请求,需要客户端每隔一段时间就请求一次服务器,再由服务器返回数据。这种传统的模式带来很明显的缺点,即客户端需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
在这种情况下,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。WebSocket只需要与服务器进行一次握手,即可实现实时的数据连接,并且传输协议是全双工的,服务器可以随时主动向客户端发送数据,并且WebSocket协议在连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小,能明显降低服务器及客户端开销。
我们的小程序也支持WebSocket通信,如果你想为你的小程序实现聊天室、服务器推送、小程序之间数据交互等功能,那就非常有必要搭建一个WebSocket服务器来进行WebSocket通讯。这篇文章中,我们将简单介绍小程序WebSocket通信使用方法,并通过实例搭建一个WebSocket服务器。实现小程序与服务器之间的通讯。
在教程开始之前,需要搭建搭建好小程序的基础开发环境,关于如何配置,大家可以参考如何入门小程序开发 这篇文章的入门 教程。
服务器搭建
既然要实现WebSocket通讯,那必须要拥有一台WebSocket服务器,服务端的环境有很多选择NodeJS、PHP、Python等大部分主流语言都可以部署WebSocket服务,今天我们将教大家使用PHP语言进行环境部署,其他语言请同学们自行部署。
运行环境搭建
我这里以Ubuntu Server 16.04 LTS为例,我们需要安装php运行环境及NginxWeb服务,同时也需要申请免费的SSL证书 和域名 ,关于证书和域名的申请注册请参考如何快速搭建微信小程序 这篇文章。注册完域名及证书申请,我们就可以开始部署服务器了!首先,登录服务器,执行下面的命令。
sudo apt update
sudo apt install php php- fpm php- curl nginx composer - y
复制
安装完成后,使用浏览器访问你的服务器IP地址,如果看到下面的内容,则证明Web服务已经启动。
img
因为小程序获取远程数据,必须为HTTPS或WSS环境,所以目前搭建的环境,在小程序无法使用,接下来,我们将使用SSL证书加密小程序访问你服务器之间的流量。这里就需要刚才注册的域名及证书了。首先,将下载的证书,上传到你的服务器,并记录下这个位置。然后,我们将配置Nginx服务,以让其支持WSS流量。
我们找到/etc/nginx/conf.d文件夹,新建配置文件,为了方便后续修改,我将这里的配置文件修改为weixin.techeek.cn.conf大家可以根据自己的需求修改。
cd / etc/ nginx/ conf. d
sudo nano weixin. techeek. cn. conf
复制
在nano编辑器中,我们写下下面的代码
server {
listen 443 ssl;
server_name weixin. techeek. cn;
index index. php index. html index. htm;
root / usr/ share/ nginx/ html;
ssl_certificate / home/ ubuntu/ 1_weixin. techeek. cn_bundle. crt;
ssl_certificate_key / home/ ubuntu/ 2_weixin. techeek. cn. key;
ssl_session_cache shared: SSL : 1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH : ! aNULL: ! MD5 ;
ssl_prefer_server_ciphers on;
location ~ . php$ {
fastcgi_pass unix: / run/ php/ php7. 0 - fpm. sock;
fastcgi_index index. php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location /
{
proxy_pass http: / / 127.0 .0 .1 : 8080 ;
proxy_http_version 1.1 ;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade" ;
proxy_set_header X - Real- IP $remote_addr;
}
}
server {
listen 80 default_server;
server_name weixin. techeek. cn;
root / usr/ share/ nginx/ html;
index index. php index. html index. htm;
location / {
try_files $uri $uri/ = 404 ;
}
}
复制
一定注意,将文中server_name中的weixin.techeek.cn更换成你的域名。将ssl_certificate和ssl_certificate_key中证书的路径更换成你刚上传证书的路径。然后,执行下面的命令重启nginx服务。
sudo service nginx restart
复制
之后,打开你电脑的浏览器,然后通过域名访问,注意,这里一定要在域名前加https://,比如我访问的域名https://weixin.techeek.cn/。
1542188355313
如果域名前有小锁标志,则证明你已经配置成功,可以开始下一步了,这里502报错不用在意,因为我们还没有搭建WebSocket服务,所以服务器会返回502错误。
配置通讯域名
基本环境配置好之后,可以登录 微信公众平台 配置通信域名了。我们点击微信公众号右侧的设置,然后找到服务器域名配置。
1542188610710
进入微信公众平台管理后台设置服务器配置,如上图所示,需要将你的服务器域名配置为你自己的域名。我这里的域名是weixin.techeek.cn。
WebSocket服务搭建
上述步骤准备完成后 ,就可以撰写WebSocket服务端的代码了,我这里使用的是PHP socket即时通讯 框架Workerman 来进行搭建。有了这个框架,我们就可以非常方便的搭建WebSocket服务。因为本文主要讲解小程序端的WebSocket的使用,关于Workerman的详细使用教程,可以参考Workerman官方手册 ,本文仅做基础环境安装的介绍。
首先,我们创建一个运行WebSocket服务的目录,我这里创建名为php-websocket-server,目录位置可以自定义,我这里就将项目放在ubuntu用户的根目录下。
mkdir / home/ ubuntu/ php- websocket- server
cd / home/ ubuntu/ php- websocket- server
复制
接下来,我们使用composer包管理器安装WebSocket运行环境。因为某些原因,国内访问composer可能会报错,所以我们需要使用国内的composer镜像。然后就可以安装Workerman了。
sudo composer config - g repo. packagist composer https: / / packagist. phpcomposer. com
sudo composer update
sudo composer require workerman/ workerman
复制
安装完成后,默认情况下会有三个文件,composer.json、composer.lock、vendor这三个文件,如果没有,请重新执行上面的命令。
├── composer. json
├── composer. lock
└── vendor
复制
安装完workerman依赖文件,我们就可以撰写系统所需的代码了。使用nano编辑器,新建一个可执行的php文件,我这里创建的文件名为webSocket.php,大家可自行更改。
代码如下
< ? php
require_once __DIR__ . '/vendor/autoload.php' ;
use Workerman\Worker;
$ws_worker = new Worker ( "websocket://0.0.0.0:8080" ) ;
$ws_worker- > count = 4 ;
$ws_worker- > onMessage = function ( $connection, $data )
{
$connection- > send ( 'hello ' . $data) ;
} ;
Worker : : runAll ( ) ;
复制
这时,一个最基本的websocket服务就编辑完成了,这里的代码意思是,通过/vendor/autoload.php引入Workerman的php文件,然后在8080端口创建websocket服务,并设置进程为4个进程。然后执行onMessage回调函数,该函数接收客户端所发过来的数据$data,然后使用send方法将数据发回给客户端。
接下来,我们就可以运行服务器了,执行下面的代码即可运行。
sudo php webSocket. php start
复制
如果看到类似下面的输出,证明我们websocket服务器已经启动,接下来就可以开始配置小程序端的代码了。
1542247109151
小程序端
连接服务器
小程序连接Websocket服务器是通过wx.connectSocket()API进行连接的,为了方便连接API,我们先看看官方的文档 。
HTTP Header,Header 中不能设置 Referer
我们看到只有url是必填项,其他属性可以不填,那么连接服务器就比较简单了,我们打开index.js文件,写下下面的代码。
Page ( {
onReady : function ( ) {
wx. connectSocket ( {
url : 'wss://weixin.techeek.cn'
} )
} ,
} )
复制
有小程序开发 经验的小伙伴都知道,这里的onReady是小程序的生命周期函数,负责在小程序初次渲染完成后执行的函数,这样我们编译完小程序,小程序就自动连接服务器。现在编译一下试试,咦,好像不行啊,怎么没看到小程序有反应。我们打开控制台,点击Network按钮,如果看到类似下面的内容,就证明你的小程序已经成功链接服务器了。
1542249696427
这里的HTTP状态码是101,101状态码是websocket特有的状态码,我们已经成功连接搭建的服务器。但是我们能不能直观点看到已经连接服务器呢?当然可以,参考文档使用success属性,我们在其中加入回调函数。修改代码如下。
Page ( {
onReady : function ( ) {
wx. connectSocket ( {
url : 'wss://weixin.techeek.cn' ,
success : function ( res ) {
console. log ( "连接服务器成功" )
} ,
fail : function ( res ) {
console. log ( "连接服务器失败" )
}
} )
} ,
} )
复制
我们增加一个回调函数,如果服务器连接成功,向小程序控制台打印出连接服务器成功。反正打印连接服务器失败。
1542250247835
当然,我们也可以将成功的内容展示给小程序前端,代码如下,首先修改index.wxml代码。
< view> < text> 连接服务器状态:{ { status} } < / text> < / view>
复制
然后打开index.js文件,修改代码
Page ( {
onReady : function ( ) {
var myThis = this ;
wx. connectSocket ( {
url : 'wss://weixin.techeek.cn' ,
success : function ( res ) {
myThis. setData ( {
status : "连接服务器成功"
} )
} ,
fail : function ( res ) {
myThis. setData ( {
status : "连接服务器失败"
} )
}
} )
} ,
} )
复制
现在重新编译小程序,你会看到类似这样的界面。
1542250497626
向服务器发送数据
服务器搭建我们说到,我们的服务器的代码内容是将小程序发给服务器的任意字符前加hello之后返回给小程序,现在,我们已经成功连接服务器了。接下来,我们需要修改代码,以便小程序将数据发给服务器。
官方文档中,使用wx.sendSocketMessage()API将数据发给服务器,根据官方文档,通过 WebSocket 连接发送数据。需要先wx.connectSocket连接服务器,并在 wx.onSocketOpen 回调之后才能发送。所以在调用wx.sendSocketMessage()前,需要先调用wx.onSocketOpen监听WebSocket连接是否打开。代码如下。
Page ( {
onReady : function ( ) {
var myThis = this ;
wx. connectSocket ( {
url : 'wss://weixin.techeek.cn'
} )
wx. onSocketOpen ( function ( res ) {
myThis. setData ( {
status : "websocket连接服务器成功"
} )
} )
} ,
} )
复制
现在,我们就可以使用wx.sendSocketMessage()发送数据到服务器了,先看看官方文档 ,怎么使用。
我们只需要传data内容给API,就能发内容给服务器了,那么修代码内容如下。
Page ( {
onReady : function ( ) {
var myThis = this ;
wx. connectSocket ( {
url : 'wss://weixin.techeek.cn'
} )
wx. onSocketOpen ( function ( res ) {
wx. sendSocketMessage ( {
data : "你好" ,
success : function ( res ) {
console. log ( "数据已发给服务器" )
}
} )
myThis. setData ( {
status : "websocket连接服务器成功"
} )
} )
} ,
} )
复制
现在,我们的数据已经可以发给服务器了,可是我们还没有看到服务器返回的数据,这时,我们就该使用另一个API了,监听WebSocket 接受到服务器的消息事件wx.onSocketMessage(),该API返回服务器发出的消息。但是onReady函数是页面加载就运行的,这时服务器还没反应过来,数据返回了没收到该怎么处理?我们可以引入另一个生命周期函数onLoad,这个函数是小程序负责监听页面加载的函数,我们可以将服务器消息事件监听的API写在这里,当接收到数据,由这个函数返回相关内容。所以代码如下。
Page ( {
onReady : function ( ) {
var myThis = this ;
wx. connectSocket ( {
url : 'wss://weixin.techeek.cn'
} )
wx. onSocketOpen ( function ( res ) {
wx. sendSocketMessage ( {
data : "你好" ,
success : function ( res ) {
console. log ( "数据已发给服务器" )
}
} )
myThis. setData ( {
status : "websocket连接服务器成功"
} )
} )
} ,
onLoad : function ( options ) {
var myThis = this ;
wx. onSocketMessage ( function ( res ) {
myThis. setData ( {
message : res. data
} )
} )
} ,
} )
复制
为了方便观察服务器返回的数据,我们修改下前端,增加服务器消息监听的内容。
< view> < text> 连接服务器状态:{ { status} } < / text> < / view>
< view> < text> 服务器消息:{ { message} } < / text> < / view>
复制
现在,重新编译,就能看到服务器返回Hello 你好的内容,我们发出的内容为你好,服务器在内容前加一个Hello然后返回给小程序。我们可以修改你好为任意内容,看看服务器能否正常返回相关内容。稍微优化下前端和后端代码,如下。
index.wxml
< button type= "primary" bindtap= "connect" > 连接webSocket服务器< / button>
< button type= "warn" bindtap= "close" > 断开webSocket服务器< / button>
< input placeholder= "在这里输入你要发送的弹幕内容" bindblur= "input" / >
< button bindtap= "send" > 向webSocket服务器发送消息< / button>
< view> < text> 连接服务器状态:{ { status} } < / text> < / view>
< view> < text> 服务器消息:{ { message} } < / text> < / view>
复制
index.js
Page ( {
connect ( ) {
var myThis = this ;
wx. connectSocket ( {
url : 'wss://weixin.techeek.cn'
} )
wx. onSocketOpen ( function ( res ) {
myThis. setData ( {
status : "websocket连接服务器成功"
} )
} )
} ,
close ( ) {
var myThis = this ;
wx. closeSocket ( )
wx. onSocketClose ( function ( res ) {
myThis. setData ( {
status : "websocket服务器已经断开"
} )
} )
} ,
send ( ) {
var myThis = this ;
wx. sendSocketMessage ( {
data : this . inputValue,
success : function ( res ) {
console. log ( "发送信息" )
wx. showToast ( {
title : '已发送' ,
icon : 'success' ,
duration : 1000
} )
} ,
fail : function ( res ) {
myThis. setData ( {
status : "请连接服务器"
} )
}
} )
} ,
input : function ( e ) {
this . inputValue = e. detail. value
} ,
onLoad : function ( options ) {
var myThis = this ;
wx. onSocketMessage ( function ( res ) {
myThis. setData ( {
message : res. data
} )
wx. showToast ( {
title : '你收到来自服务器的消息' ,
icon : 'none' ,
duration : 2000
} )
} )
} ,
} )
复制
1542253679047
这样,我们就实现了向服务器发送数据,同时服务器返回数据的全部流程。
服务器主动发送数据到小程序
有人可能会问,这个HTTP通信方式没有区别啊,还是小程序先请求数据到服务器,然后服务器返回数据啊,我没看到什么不同。虽然表现是这样,但是现在小程序和服务器是长连接状态,服务器可以直接推送内容到小程序,不信?我们试试。打开你的服务器 Websocket.php文件,将代码修改为下面的内容。
< ? php
require_once __DIR__ . '/vendor/autoload.php' ;
use Workerman\Worker;
use Workerman\Lib\Timer;
$worker = new Worker ( 'websocket://0.0.0.0:8080' ) ;
$worker- > onWorkerStart = function ( $worker ) {
Timer : : add ( 10 , function ( ) use ( $worker ) {
foreach ( $worker- > connections as $connection ) {
$connection- > send ( '你好!' ) ;
}
} ) ;
} ;
$worker- > onMessage = function ( $connection, $data )
{
echo $data . "\n" ;
$connection- > send ( '服务器已经收到了你的消息' ) ;
} ;
Worker : : runAll ( ) ;
复制
然后运行服务器。
sudo php webSocket. php start
复制
这行代码中,我们实现了小程序连接服务器后,服务器每隔10秒主动推送数据你好给小程序,无需小程序主动请求内容,同时,小程序发出的内容,可以在服务端显示。现在点击你小程序连接webSocket服务器按钮,看看效果。
1542254161118
然后我们向服务器发点消息试试。服务器也已经收到了小程序发出的数据。
1542254236499
总结
websocket通信在小程序端还是比较简单的,赶快去自己试试吧~后续我还会介绍一篇利用websocket通讯进行聊天室搭建的教程,喜欢的小伙伴请持续关注本专栏 。腾讯云联合小程序给大家带来了小程序·云开发解决方案 ,为开发者提供完整的云端支持,弱化后端和运维操作,使用平台原生 API 进行核心业务开发,实现快速上线和迭代。欢迎免费使用!