使用strophe.js連接openfire服務器實現web端即時通訊

最近公司需要做一個簡單的即時通訊功能,因爲不是什麼主要的功能板塊,而且資金有限,所以要求要用開源的。之前自己用過環信還有極光,但是這兩個都是要收費的。後面查了一段時間以後,選擇用openfire作爲服務端,strophe.js作爲客戶端來進行開發。主要實現了,文字、圖片、視頻、位置、文件發送,開發過程中遇到的問題還是蠻多的,這裏就記錄一下,以便以後參考!

首先是openfire服務器,服務器下載安裝這裏就不多說了,網上一搜一大堆,可以參考這篇文章:https://blog.51cto.com/favccxx/1618995

 服務器搭建好了以後,需要幾個東西:

1,服務器地址:http://zhangyh:7070/http-bind/ 

2,服務器名稱:zhangyh

3,創建兩個用戶,用於後面進行聊天:admin和x5411

注意:用戶創建這裏有個小坑,不能用中文,不能用大寫字母!

好了,現在服務端的東西都準備好了,剩下的就是客戶端了,客戶端這裏,在選用strophe之前,試過converse.js和websocket,converse的話,用起來倒是挺方便的,但是如果你要自定義你自己的界面,想自己把各個模塊分離出來的話超級麻煩,而且,它的開發文檔,看起來只有那麼操蛋了,直接pass掉。然後websocket的話,因爲不是現成的,所有的包括連接,登錄,發送,接收都要自己一步步的慢慢寫,慢慢實現,用起來不是很方便。但是感覺如果想搞得好一點的話,使用websocket應該會好一點!最後,就選用了strophe。

開始客戶端的開發:頁面需要引入strophe.js,然後就可以開始了

<script type="text/javascript" src="http://cdn.bootcss.com/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="http://cdn.bootcss.com/strophe.js/1.1.3/strophe.min.js"></script>

1,連接openfire服務器,登錄,注意:登錄的用戶名,後面需要拼上服務器的名稱,如:admin@zhangyh

    //登錄openfire
    function loginOpenfire() {
 		// 初始化strophe.js,獲取當前賬戶的登錄信息
		let service = Constant.OPENFIRE_BOSH_SERVICE;//服務器地址
		window.connection = new Strophe.Connection(service);
        //剛纔創建的用戶的賬號和密碼
 		let userName = Constant.OPENFIRE_ACCOUNT_NAME;//admin@zhangyh
 		let passWord = Constant.OPENFIRE_ACCOUNT_PASSWORD;//admin@123
        //開始登錄,完成登錄以後,會有個回調方法onConnect
        connection.connect(userName, passWord, function(status){
        	onConnect(status)
        });
    }

    /**
	 * 連接狀態改變時觸發
	 */  
	function onConnect(status) {
		if (status == Strophe.Status.CONNFAIL) {
			alert("連接失敗,網絡異常!");
		} else if (status == Strophe.Status.AUTHFAIL) {
			alert("登錄失敗,賬號或密碼錯誤!");
		} else if (status == Strophe.Status.DISCONNECTED) {
			alert("連接斷開了!");
			//這裏可以根據自己的業務邏輯來處理,要保持登錄就調用登錄方法
			loginOpenFire();
		} else if (status == Strophe.Status.CONNECTED) {
			console.log("連接成功,可以開始聊天了!");
			// 當接收到消息時,調用reMessage回調函數  
			connection.addHandler(function(msg){
				reMessage(msg);
			}, null, 'message', null, null, null);
			// 首先要發送一個<presence>給服務器(initial presence),這一步必須做,要不然服務器不知道你到底要幹嘛
			connection.send($pres().tree());
		}
	}

2,發送聊天信息

    /**
     * 發送聊天信息
     */    
    function sendText() {
        var val = "發送內容";//需要發送的文字內容
		// 創建一個<message>元素併發送  
		var msg = $msg({
			to: sendTo,//發送對象的用戶名 x5411@zhangyh
			from: jid,//發送人 admin@zhangyh
			type: 'chat'
		}).c("body", null, val);
		connection.send(msg.tree());
		console.log(msg.tree());
    }

3,接收聊天信息

    /**
	 * 收到消息
	 */
	function reMessage(msg) {
		// 解析出<message>的from、type屬性,以及body子元素  
		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];
            alert("接收到的消息是:"+Strophe.getText(body));
		}
		return true;
    }

這裏遇到個問題,我在寫demo的時候,用的是原生的js寫的,所以監聽收到消息的觸發,只需要在onConnect方法裏面做一次就可以了,但是實際開發環境是用的react開發的,實際運行的時候接收消息的監聽執行一次以後,後面就不會執行了,就導致正式聊天的時候第一次可以收到消息,後面就就接收不到了!百度到的一個比較接近的答案是,因爲strophe.js裏面在消息監聽裏面做了try{}catch{},然後正式環境裏面進行消息監聽的時候捕捉到了項目其它地方的異常信息,strophe以爲消息監聽異常沒有完成,所以就銷燬了這個監聽(但是實際上是正常的)。感覺應該就是這個原因導致的,但是我把所有源碼裏面的異常捕捉都去掉了以後還是不行,所以就在每次監聽完成接收到消息以後,再啓用一次監聽,這樣即使上一個被銷燬了,監聽還是可以有效。

 /**
	 * 收到消息
	 */
	function reMessage(msg) {
		// 解析出<message>的from、type屬性,以及body子元素  
		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];
            alert("接收到的消息是:"+Strophe.getText(body));
		}
		//每次收到消息以後都要進行下一次監聽,如果不做這一步,就只能監聽一次(未解決)
		connection.addHandler(function(msg){
			reMessage(msg);
		}, null, 'message', null, null, null);
		return true;
    }

上面就是一個簡單的,登錄、發送、接收的過程了!

然後問題又來了,strophe只用用於簡單的文字聊天,涉及到文件的東西,需要借用到第三方的插件,XEP-0096: SI File Transfer,所以又去研究了一下文件傳輸的問題。研究了大半天,都沒搞明白這東西是怎麼傳輸的,光是文件傳輸的消息通知都沒調通,一直報503(估計是我太菜了,有時間再繼續研究下)。沒辦法,項目又催的比較急,只能另闢蹊徑了!然後就想到了一個辦法(這裏不得不佩服一下我的機智了)。

這個辦法是這樣的,正常接收到的文字聊天信息是這樣的<message><body>接收到消息了</body></message>,如果對方發送的是一個對象的話,比如 {name:123,type:456} ,那接收到的消息就是這樣的<message><body name="123" type="456"></body></message>,所以,只要涉及到文件上傳的,先將文件上傳到我們自己的服務器上面,獲取文件路徑以後,將文件的所有信息以對象的形式發送給對方 ,對方接收到消息以後,根據body裏面的type屬性來區分發送方發送的是文字還是文件(圖片,視頻、位置同理)。

發送文件信息的完整過程:

1,選擇文件

2,上傳文件獲取文件的完整路徑、名稱、大小等

3,將文件的信息封裝成一個對象以文字的形式發送給接收方

4,這個時候接收方接收到消息以後,就可以進行解析,根據文件類型來進行展示

strophe和openfire這個東西實在太老了,網上描述倒是挺多的,但是真正開發的實例太少了,遇到問題都得自己慢慢摸索。過程雖然很坎坷,但是總算是搞完了!歡迎交流,一起進步!如果有什麼說的不對的,歡迎指出哈!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章