通过 websocket 连接 openfire
项目下载地址:https://github.com/liuwenhaoCN/openfire/tree/websocket
一、简介
老版本是需要安装websocket插件的。之前版本就不说了。
二、 引入XML与JSON互转的js
<script src="lib/XML/ObjTree.js"></script>
<script src="lib/XML/jkl-dumper.js"></script>
自行百度下载新版本。我使用的版本上传至百度网盘:
链接: https://pan.baidu.com/s/1ALWJPAbb14yKtsY_CTj1Gg 提取码: vfc3
使用方法:
//json转xml
function json2xml(jsonstring) {
var xotree = new XML.ObjTree();
var xml = xotree.writeXML(jsonstring);
//使用jkl-dumper.js中的formatXml方法将xml字符串格式化
//var xmlText = formatXml(xml);
return xml;
}
//xml转json
function xml2json(xmlstring) {
//将xml字符串转为json
var xotree = new XML.ObjTree();
var json = xotree.parseXML(xmlstring);
//将json对象转为格式化的字符串
var dumper = new JKL.Dumper();
var jsonText = dumper.dump(json);
return JSON.parse(jsonText);
}
三、使用
1. 先获取安装的服务器地址
在http://192.168.2.11:9090/index.jsp 首页面可以看到以下信息:
服务器属性
服务器启动时间: 20 天, 23 小时, 22 分钟 -- started 2018-9-5 15:44:47
版本: Openfire 4.2.2
Openfire 主目录: /var/openfire
服务器名称: lvs-backup-1
环境
JVM 版本和供应商: 1.8.0_65 Oracle Corporation -- Java HotSpot(TM) 64-Bit Server VM
应用服务器: jetty/9.2.z-SNAPSHOT
主机名: lvs-backup-1
OS/硬件: Linux / amd64
语言环境/时区: zh_CN / 中国标准时间 (8 GMT)
服务器端口
所有的地址 7070 HTTP绑定 端口用于客户端使用不安全的HTTP方式访问
所有的地址 7443 端口用于网络上以SSL加密的通信,HTTP绑定端口用于客户端使用安全的HTTP方式访问
2. 创建websocket
//地址
var host = "ws://192.168.2.11:7070/ws/";
//创建websocket, OpenFire是实现了WebSocket的子协议
websocket = new WebSocket(host, 'xmpp');
//连接成功建立的回调方法
websocket.onopen = wsopen;
//连接发生错误的回调方法
websocket.onerror = wserror;
//连接关闭的回调方法
websocket.onclose = wsclose;
//收到消息时执行的方法
websocket.onmessage = wsmessage;
当websocket连接成功,就需要发起建立流的请求
3. 发起建立流的请求
发送xml
<?xml version="1.0" encoding="UTF-8" ?>
<open to="lvs-backup-1" from="AA@lvs-backup-1" xmlns="urn:ietf:params:xml:ns:xmpp-framing" xml:lang="zh" version="1.0" />
方法
//域名
var to = "lvs-backup-1";
//JID
var from = AA@lvs-backup-1;
var xmlns = "urn:ietf:params:xml:ns:xmpp-framing";
var version = "1.0";
var xmllang = "zh";
var resource = "appClient";
//发起建立流的请求
function connwsopen() {
var temp = {
"open": {
"-to": to,
"-from": from,
"-xmlns": xmlns,
"-xml:lang": xmllang,
"-version": version
}
};
//转化为xml
var steam = json2xml(temp);
websocket.send(steam);
}
接收XML
服务器返回同意建立流
<open to='AA@lvs-backup-1' from='lvs-backup-1' id='1g0xa0mr98' xmlns='urn:ietf:params:xml:ns:xmpp-framing' xml:lang='zh' version='1.0'/>
安全验证的方式,使用PLAIN方式,这种方式是把用户名和密码通过BASE64加密后传输。
<stream:features xmlns:stream='http://etherx.jabber.org/streams'><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism><mechanism>SCRAM-SHA-1</mechanism><mechanism>CRAM-MD5</mechanism><mechanism>DIGEST-MD5</mechanism></mechanisms></stream:features>
4.登录
使用PLAIN方式,需要对用户名和密码通过BASE64加密
字符串格式是:jid+password,以\0作为分隔符
var temp = username + "@" + to + "\0" + password;
//Base64编码
var token = window.btoa(temp);
发送XML
<?xml version="1.0" encoding="UTF-8" ?>
<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">MTUyNzUwNzYzNTNAbHZzLWJhY2t1cC0xAGUxMGFkYzM5NDliYTU5YWJiZTU2ZTA1N2YyMGY4ODNl</auth>
方法
//登录验证
function validatelogin() {
//字符串格式是:jid+password,以\0作为分隔符
var temp = username + "@" + to + "\0" + password;
//Base64编码
var token = window.btoa(temp);
var message = {
"auth": {
"-xmlns": "urn:ietf:params:xml:ns:xmpp-sasl",
"-mechanism": "PLAIN",
"#text": token
}
};
websocket.send(json2xml(message));
}
接收XML
登录成功:
<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>
登录失败:
<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><not-authorized/></failure>
登录验证成功后,需要再发起一个新的流,新的流服务端会给予一些新的XML节点权限(、),这样才能发送一些其他功能的信息,比如发送消息,获取联系人列表,刚开始建立的第一个流失不能发送这些节点的。
5.发起新的流
在发起新的流之前,需要获取到第一个流的id,这个id就是与websocket的会话差不多。
发送XML
<?xml version="1.0" encoding="UTF-8" ?>
<open xmlns="jabber:client" to="lvs-backup-1" version="1.0" from="AA@lvs-backup-1" id="1g0xa0mr98" xml:lang="zh" />
方法
id = "1g0xa0mr98"; 第一个流的id
//发起新的流
function newopen() {
var temp = {
"open": {
"-xmlns": "jabber:client",
"-to": to,
"-version": version,
"-from": from,
"-id": id,
"-xml:lang": xmllang
}
};
//转化为xml
var steam = json2xml(temp);
websocket.send(steam);
}
接收XML
同意打开新流
<open to='AA@lvs-backup-1' from='lvs-backup-1' id='1g0xa0mr98' xmlns='urn:ietf:params:xml:ns:xmpp-framing' xml:lang='zh' version='1.0'/>
接下来需要做bind操作
<stream:features xmlns:stream='http://etherx.jabber.org/streams'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><session xmlns='urn:ietf:params:xml:ns:xmpp-session'><optional/></session><sm xmlns='urn:xmpp:sm:3'/></stream:features>
6. bind
绑定操作,也需要id的,在绑定的时候,可以增加客户端的描述。
appClient:是app的客户端
发送XML
<?xml version="1.0" encoding="UTF-8" ?>
<iq id="1g0xa0mr98" type="set">
<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">
<resource>appClient</resource>
</bind>
</iq>
方法
//bind操作
function bind() {
var temp = {
"iq": {
"-id": id,
"-type": "set",
"bind": {
"-xmlns": "urn:ietf:params:xml:ns:xmpp-bind",
"resource":resource
}
}
};
//转化为xml
var steam = json2xml(temp);
websocket.send(steam);
}
接收
<iq xmlns="jabber:client" type="result" id="1g0xa0mr98" to="lvs-backup-1/8itpfrge4k"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>AA@lvs-backup-1/appClient</jid></bind></iq>
7. 获取session
发送XML
<?xml version="1.0" encoding="UTF-8" ?>
<iq xmlns="jabber:client" id="1g0xa0mr98" type="set">
<session xmlns="urn:ietf:params:xml:ns:xmpp-session" />
</iq>
方法
//获取session
function getsession() {
var temp = {
"iq": {
"-xmlns": "jabber:client",
"-id": id,
"-type": "set",
"session": {"-xmlns": "urn:ietf:params:xml:ns:xmpp-session"}
}
};
//转化为xml
var steam = json2xml(temp);
websocket.send(steam);
}
接收
<iq xmlns="jabber:client" type="result" id="1g0xa0mr98" to="AA@lvs-backup-1/appClient"/>
这个时候,在web页面会话中看到的,账号还是离线状态。对应的消息也收不到。下一步就需要做上线的操作了。
7. 上线
发送XML
<?xml version="1.0" encoding="UTF-8" ?>
<presence id="1g0xa0mr98">
<status>online</status>
<priority>1</priority>
</presence>
方法
priority:设置优先级的
//上线
function presence() {
var temp = {
"presence": {
"-id": id,
"status": "online",
"priority": "1"
}
};
//转化为xml
var steam = json2xml(temp);
websocket.send(steam);
}
接收XML
会把对应的好友发送过来
<presence xmlns="jabber:client" from="BB@lvs-backup-1" to="AA@lvs-backup-1" type="subscribe"/>
<presence xmlns="jabber:client" from="CC@lvs-backup-1" to="AA@lvs-backup-1" type="subscribe"/>
这时候再看web中的会话,该账号就在线了。
8. 发送消息
发送XML
body:对应的消息内容
<?xml version="1.0" encoding="UTF-8" ?>
<message type="chat" from="AA@lvs-backup-1" to="BB@lvs-backup-1">
<subject>标题</subject>
<body>你好</body>
</message>
方法
number:给谁发
message:消息内容
//发消息
function send(number,message) {
var temp = {
"message": {
"-type":"chat",
"-from": username+"@"+to,
"-to": number+"@"+to,
"subject":"标题",
"body": message
}
};
//转化为xml
var steam = json2xml(temp);
websocket.send(steam);
}
四、 过程
用户名: 15275076353
密码: e10adc3949ba59abbe56e057f20f883e
正在连接..
连接已建立
发起建立流的请求: <?xml version="1.0" encoding="UTF-8" ?>
<open to="lvs-backup-1" from="15275076353@lvs-backup-1" xmlns="urn:ietf:params:xml:ns:xmpp-framing" xml:lang="zh" version="1.0" />
接收到的 <open to='15275076353@lvs-backup-1' from='lvs-backup-1' id='3r01w7mpew' xmlns='urn:ietf:params:xml:ns:xmpp-framing' xml:lang='zh' version='1.0'/>
接收到的 <stream:features xmlns:stream='http://etherx.jabber.org/streams'><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
<mechanism>PLAIN</mechanism><mechanism>SCRAM-SHA-1</mechanism><mechanism>CRAM-MD5</mechanism><mechanism>DIGEST-MD5</mechanism></mechanisms>
</stream:features>
登录验证: <?xml version="1.0" encoding="UTF-8" ?>
<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">MTUyNzUwNzYzNTNAbHZzLWJhY2t1cC0xAGUxMGFkYzM5NDliYTU5YWJiZTU2ZTA1N2YyMGY4ODNl</auth>
接收到的 <success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>
登录成功!
发起新的流: <?xml version="1.0" encoding="UTF-8" ?>
<open xmlns="jabber:client" to="lvs-backup-1" version="1.0" from="15275076353@lvs-backup-1" id="3r01w7mpew" xml:lang="zh" />
接收到的 <open to='15275076353@lvs-backup-1' from='lvs-backup-1' id='3r01w7mpew' xmlns='urn:ietf:params:xml:ns:xmpp-framing'
xml:lang='zh' version='1.0'/>
接收到的 <stream:features xmlns:stream='http://etherx.jabber.org/streams'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'><optional/></session><sm xmlns='urn:xmpp:sm:3'/></stream:features>
bind操作: <?xml version="1.0" encoding="UTF-8" ?>
<iq id="3r01w7mpew" type="set">
<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">
<resource>appClient</resource>
</bind>
</iq>
接收到的 <iq xmlns="jabber:client" type="result" id="3r01w7mpew" to="lvs-backup-1/3r01w7mpew"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>15275076353@lvs-backup-1/appClient</jid></bind></iq>
获取session: <?xml version="1.0" encoding="UTF-8" ?>
<iq xmlns="jabber:client" id="3r01w7mpew" type="set">
<session xmlns="urn:ietf:params:xml:ns:xmpp-session" />
</iq>
接收到的 <iq xmlns="jabber:client" type="result" id="3r01w7mpew" to="15275076353@lvs-backup-1/appClient"/>
上线: <?xml version="1.0" encoding="UTF-8" ?>
<presence id="3r01w7mpew">
<status>online</status>
<priority>1</priority>
</presence>
接收到的 <presence xmlns="jabber:client" from="11112222333@linux" to="15275076353@lvs-backup-1" type="subscribe"/>
接收到的 <presence xmlns="jabber:client" from="13121372109@linux" to="15275076353@lvs-backup-1" type="subscribe"/>