使用Strophe連接xmpp,輕松構(gòu)建web即時聊天工具。
實現(xiàn)原理
實現(xiàn)webim方法有很多,最關(guān)鍵的問題是保持和服務(wù)端的連接。如何保障會話的即時性和連通性。常用的有poll, long poll, comet等;; 其中poll的方式效果最差,一般都會有1到2秒的延遲。long poll和comet技術(shù)比較新,因為http無狀態(tài)的原因,這種長連接方式要保持,一般都需要服務(wù)端額外代碼提供支持。像gtalk采用的就是long poll的方式。服務(wù)端常會使用異步IO等方式來支持高并發(fā)。
本文使用的是XEP標(biāo)準(zhǔn)擴(kuò)展規(guī)范,XEP-0124 提供的方法實現(xiàn)WebIM. 思路即使用一個javascript的xep-0124的實現(xiàn),直接連接xmpp server端。目前xep-0124的實現(xiàn),在大部分的xmpp server實現(xiàn)中都支持,本文使用的是OpenFire 3.6.4 作為Xmpp Server。
XEP 0124規(guī)范定義了一個比較完整和安全的協(xié)議,具體請參閱相當(dāng)文檔。本文使用javascript端的XEP-0124的實現(xiàn)為Strophe的js實現(xiàn)。
另外因為瀏覽器javascript跨域問題,需要使webim里調(diào)用javascript也是80端口,并同一子域,所以使用Apache或者Nginx 在80端口,并轉(zhuǎn)發(fā)/http-bind請求至Xmpp Server的http-binding端口。本機使用Nginx. xmpp server 使用使用7070端口。
一、安裝openfire:http://blog.csdn.net/e421083458/article/details/38037373
二、配置apache
我們下載安裝的是httpd-2.2.17-win32-x86-no_ssl.msi,安裝完成后,我們需要配置一下,由于jwchat是用javacript去和openfire進(jìn)行通訊的,所以他們之間的通訊是基于http的,但是由于瀏覽器為了安全性是不允許javascript跨域訪問的。我們必須通過別的技術(shù)來繞過這限制,所以我們采取apache服務(wù)器的重定向功能去突破這個限制。
安裝完成后進(jìn)入到apache的安裝目找到conf文件夾下的httpd.conf文件,用記事本打開,把下列幾個配置項放開(默認(rèn)被注釋掉了)
1、LoadModule rewrite_module modules/mod_rewrite.so
2、LoadModule proxy_module modules/mod_proxy.so
3、LoadModule proxy_http_module modules/mod_proxy_http.so
然后再在本配置文件的末尾加入如下幾行配置
ServerName blzc.com
<Directory /var/jwchat>
Options +Indexes +MultiViews
</Directory>
AddDefaultCharset UTF-8
RewriteEngine on
ProxyPass /jwchat/http-bind/ http://blzc.com:7070/http-bind/
在此有必要對proxyPass的參數(shù)做些說明
“/jwchat/http-bind/”:jwchat就通過訪問http://域名/jwchat/http-bind/地址去和openfire通訊,apache接到請求后就會重新定向到http://blzc.com:7070/http-bind/
“http://blzc.com:7070/http-bind/”:被重新定向的地址,也就是我們的openfire的http訪問地址。7070端口是openfire的默認(rèn)訪問端口,當(dāng)然我們也可以進(jìn)入openfire進(jìn)行配置。
三、openfire的配置
安裝好openfire后進(jìn)入web式的管理界面,選擇服務(wù)器-》服務(wù)器管理器-》系統(tǒng)屬性
在里邊添加兩個屬性(記得選擇不加密)
xmpp.httpbind.client.requests.polling = 0
xmpp.httpbind.client.requests.wait = 10
四、創(chuàng)建聊天腳本
創(chuàng)建index.html頁面:
- <!DOCTYPE html>
- <html>
- <head>
- <title>Latest content</title>
- <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
- <script type="text/javascript"
- src="strophejs/strophe.js"></script>
- <script type="text/javascript"
- src="pingstream.js"></script>
- </head>
- <body>
- <div id='login' style='text-align: left'>
- <form name='cred'>
- <label for='jid'>JID:</label>
- <input type='text' id='jid' value="richard@csdn.shimiso.com" /><br/>
- <label for='pass'>Password:</label>
- <input type='password' id='pass' value="niuyufu123" /><br/>
- <input type='button' id='connect' value='connect' />
- </form>
- </div>
- <hr />
- <div style="text-align: left">
- <label for='tojid'>tojid</label>
- <input type='text' id='tojid' value="" /><br/>
- <label for='msg'>msg:</label>
- <textarea id="msg">Hello world!!!</textarea>
- <br/>
- <input type='button' id='replay' value='replay' />
- </div>
- <hr />
- <div id='log'></div>
- </body>
- </html>
創(chuàng)建pingstream.js
- var BOSH_SERVICE = '/http-bind/';
- var connection = null;
-
- function log(msg)
- {
- $('#log').append('<div></div>').append(document.createTextNode(msg));
- }
-
- /**
- * 連接綁定方法
- * @param status
- */
- function onConnect(status)
- {
- if (status == Strophe.Status.CONNECTING) {
- log('Strophe is connecting.');
- } else if (status == Strophe.Status.CONNFAIL) {
- log('Strophe failed to connect.');
- $('#connect').get(0).value = 'connect';
- } else if (status == Strophe.Status.DISCONNECTING) {
- log('Strophe is disconnecting.');
- } else if (status == Strophe.Status.DISCONNECTED) {
- log('Strophe is disconnected.');
- $('#connect').get(0).value = 'connect';
- } else if (status == Strophe.Status.CONNECTED) {
- log('Strophe is connected.');
- log('ECHOBOT: Send a message to ' + connection.jid +
- ' to talk to me.');
-
- connection.addHandler(onMessage, null, 'message', null, null, null);
- connection.send($pres().tree());
- }
- }
-
- /**
- * 獲取消息時的方法
- * @param msg
- * @returns {Boolean}
- */
- function onMessage(msg) {
- var to = msg.getAttribute('to');
- var from = msg.getAttribute('from');
- var type = msg.getAttribute('type');
- var elems = msg.getElementsByTagName('body');
-
- if (type == "chat" && elems.length > 0) {
- var body = elems[0];
-
- log('ECHOBOT: I got a message from ' + from + ': ' +
- Strophe.getText(body));
-
- /* 關(guān)閉echo機器的自動回復(fù)
- var reply = $msg({to: from, from: to, type: 'chat'})
- .cnode(Strophe.copyElement(body));
- connection.send(reply.tree());
-
- log('ECHOBOT: I sent ' + from + ': ' + Strophe.getText(body));*/
-
-
- }
- return true;
- }
-
- /**
- * 發(fā)信息
- * @param toId
- * @param fromId
- * @param msg
- */
- function sendMsg(toId,fromId,msg) {
- var reply = $msg({to: toId, from:fromId , type: 'chat'}).cnode(Strophe.xmlElement('body', '' ,msg));
- connection.send(reply.tree());
- log('ECHOBOT: I sent ' + toId + ': ' + msg);
- }
-
- /**
- * 事件監(jiān)聽
- */
- $(document).ready(function () {
- connection = new Strophe.Connection(BOSH_SERVICE);
-
- // Uncomment the following lines to spy on the wire traffic.
- connection.rawInput = function (data) { console.log('RECV: ' + data); };
- connection.rawOutput = function (data) { console.log('SEND: ' + data); };
-
- // Uncomment the following line to see all the debug output.
- //Strophe.log = function (level, msg) { log('LOG: ' + msg); };
-
- $('#connect').bind('click', function () {
- var button = $('#connect').get(0);
- if (button.value == 'connect') {
- button.value = 'disconnect';
- connection.connect($('#jid').get(0).value,
- $('#pass').get(0).value,
- onConnect);
- } else {
- button.value = 'connect';
- connection.disconnect();
- }
- });
-
- $('#replay').bind('click', function () {
- toId = $('#tojid').val();
- fromId = $('#jid').val();
- msg=$('#msg').val();
- sendMsg(toId,fromId,msg);
- });
- });
用pandian與聊天頁并行測試。
成功后的截圖:
代碼下載地址:http://download.csdn.net/detail/e421083458/7672297
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請
點擊舉報。