前端消息的實時推送我相信不少人不陌生,咱們能夠想到利用WebSocket,服務端主動向客戶端推送數據,瀏覽器和服務器只須要完成一次握手,二者之間就直接能夠建立持久性的鏈接,並進行雙向數據傳輸。其優勢有不少,能更好的節省服務器資源和帶寬,而且可以更實時地進行通信等等。語音播報則可以在人們視覺沒有來的及關注時侯,經過聽覺來獲取須要信息。javascript
這篇文章主要介紹的是基於websocket,利用Stomp.js以及HTML5語音Web Speech API——SpeechSynthesis來實現前端消息的實時推送與語音播報。css
讓咱們先了解一下STOMP(the Simple (or Streaming) Text Orientated Messaging Protocol)——面向消息(或流)的簡單文本協議。它提供了一個可互操做的鏈接格式,容許STOMP客戶端與任意STOMP消息代理(Broker)進行交互。html
WebSocket的實現客戶端看起來比較簡單,可是須要與後臺進行很好的配合和調試才能達到最佳效果。經過SockJS 、Stomp來進行瀏覽器兼容,能夠增長消息語義和可用性。簡而言之,WebSocket 是底層協議,SockJS 是WebSocket 的備選方案,也是底層協議,而 STOMP 是基於 WebSocket(SockJS)的上層協議。前端
下面簡單的介紹一下經常使用的方法。
在web瀏覽器中咱們能夠經過兩種方式進行客戶端的建立:
一、使用普通的WebSocketjava
let url = "ws://localhost:61614/stomp"; let client = Stomp.client(url);
二、使用定製的WebSocket
若是須要使用其餘類型的Websocket(例如由SockJS包裝的Websocket),就利用下面的方式建立客戶端react
let url = "ws://localhost:61614/stomp"; let socket = new SockJS(url); let client = Stomp.over(socket);
除上面的客戶端建立方式不一樣外,後續的鏈接等操做都是同樣的。web
咱們能夠用client.connect()
方法來鏈接服務端chrome
client.connect(login,passcode,successCallback,errorCallback);
其中login
和passcode
都是字符串,至關因而用戶的登陸名和密碼憑證。successCallback
爲鏈接成功的回調函數,errorCallback
爲鏈接失敗的回調函數。
還能夠這樣寫:apache
client.connect({ login:'name', passcode:'666', 'token':'2333' },successCallback,errorCallback);
斷開鏈接:segmentfault
client.disconnect(function(){console.log("再見")})
heart-beating也就是消息傳送的頻率,incoming
是接收頻率,outgoing
是發送頻率,其默認值都爲10000ms,咱們能夠手動設置:
client.heartbeat.outgoing = 5000; client.heartbeat.incoming = 0;
客戶端向服務端發送消息利用send()
方法,此方法有三個參數:第一個參數(string)必需,爲發送消息的目的地;第二個參數(object)可選,包含了額外的頭部信息;第三個參數(string)可選,爲發送的消息。
client.send(destination, {}, body);
訂閱消息也就是客戶端接收服務端發送的消息,訂閱消息能夠利用subscribe()
方法,此方法有三個參數:第一個參數(string)必需,爲接收消息的目的地;第二個參數必需爲回調函數;第三個參數{object}爲可選,包含額外的頭部信息。
client.subscribe(destination, callback, {});
取消訂閱消息能夠利用unsubscribe()
方法:
let mySubscribe = client.subscribe; mySubscribe.unsubscribe();
客戶端訂閱消息能夠訂閱廣播,以下所示:
client.subscribe('/topic/msg',function(messages){ console.log(messages); })
也能夠進行一對一消息的接收:
//第一種方式 const userId = 666; client.subscribe('/user/' + userId + '/msg',,function(messages){ console.log(messages); }) //第二種方式 client.subscribe('/msg',function(messages){ console.log(messages); }, {"userId ": userId })
客戶端採用的寫法要根據服務端代碼來作選擇。
在HTML5中,與語音相關的Web Speech API能夠分爲兩種:一種爲語音識別(Speech Recognition),另外一種爲語音合成(Speech Synthesis)。他們的做用分別爲「語音轉文字」和「文字轉語音」。
既然是HTML5中的東西,咱們仍是要先看看他們的兼容性如何:
Speech Recognition:
Speech Synthesis:
從上面的圖中能夠看出:語音識別(Speech Recognition)很慘烈,大部分瀏覽器還不支持。語音合成(Speech Synthesis)除開IE和Opera,基本上都支持了。
本文要實現的是語音播報,就是要把文字消息,轉成語音播報出來,而語音合成(Speech Synthesis)就是實現這樣的功能,並且兼容性也是不錯的,因此咱們就能拿來使用啦~
語音識別(Speech Recognition)就不過多介紹了,咱們來詳細看看語音合成(Speech Synthesis)。咱們能夠先把下面這段代碼打到瀏覽器的控制檯上:
let speechInstance = new window.SpeechSynthesisUtterance('你好,能夠交個朋友嗎'); window.speechSynthesis.speak(speechInstance);
不出意外,瀏覽器說話了,說明瀏覽器是支持這個API的。下面簡單介紹一下相關的屬性和方法:
SpeechSynthesisUtterance對象的屬性:
屬性 | 類型 | 描述 |
---|---|---|
text | string | 須要要讀的內容 |
lang | string | 使用的語言(好比:"zh-CN") |
volume | number | 音量,值在0-1之間(默認是1) |
rate | number | 語速的倍數,值在0.1-10之間(默認1倍) |
pitch | number | 音高,值在0-2之間,(默認是1) |
voice | string | 指定但願使用的聲音 |
SpeechSynthesisUtterance對象的方法:
方法 | 描述 |
---|---|
onstart | 語音開始合成時觸發 |
onpause | 語音暫停時觸發 |
onresume | 語音合成從新開始時觸發 |
onend | 語音結束時觸發 |
上述定義的speechInstance實際上是咱們建立的文本實例,而真實的語音是由speechSynthesis來建立的,其經常使用的方法以下:
方法 | 描述 |
---|---|
speak() | 開始合成語音,將對應的實例添加到語音隊列中 |
cancel() | 中止合成語音,刪除隊列中全部的語音 |
pause() | 暫停語音合成 |
resume() | 恢復暫停後的語音 |
getVoices() | 返回瀏覽器所支持的語音包數組 |
上面介紹了StompJS和SpeechSynthesis經常使用的屬性和方法,是時候動手碼一碼了。
想要接收實時消息,咱們當先然要有消息的來源對不對。消息是從後臺發來的,通常是利用Java,而後結合ActiveMQ或者RabbitMQ等消息中間件,Java代碼就很少說,咱們接下來就利用ActiveMQ來模擬服務端向客戶端發送消息。
這裏說一說windows環境下吧,首先要下載ActiveMQ,直接點擊官網:
http://activemq.apache.org/do...
選擇最新發佈下來的壓縮包,解壓便可,而後進入解壓後的bin目錄,能夠看見裏面有兩個文件夾,win32和win64,這個就根據本身電腦的操做系統來選擇,點擊進去,再雙擊activemq.bat啓動,若是看見下面這樣就說明啓動成功:
若是沒有啓動成功,那多半是由於沒有jdk,點這裏,跟着安裝就歐克啦~
安裝完畢後,再雙擊activemq.bat,如今咱們就啓動成功了。在瀏覽器中輸入:http://localhost:8161,能夠看到:
點擊Manage ActiveMQ broker,用戶名和密碼都是admin,而後再點擊Topics
在輸入框中輸入msg,而後點擊create按鈕
能夠看見下方列表中多了一個Name爲msg的Topics
其中須要注意的是下面幾項,以msg爲例:
模擬「服務端」準備就緒。
這「服務端」搞好了,接下來就是客戶端的實現,代碼貼出來index.html
:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>實時語音播報</title> </head> <body> <script src="http://cdn.bootcss.com/stomp.js/2.3.3/stomp.js"></script> <script> window.onload = function() { let data = ''; //創建鏈接 function connect(){ let client; let url = 'ws:127.0.0.1:61614/stomp'; client = Stomp.client(url); client.heartbeat.outgoing=0; client.connect({}, //鏈接成功回調 function connectCallback() { console.log("鏈接成功~"); //訂閱消息 // 由於咱們訂閱的是topic下的msg,因此這裏是'/topic/msg' client.subscribe('/topic/msg', function(message){ if(message.body){ data = message.body; console.log(message.body); } }) }, //鏈接失敗回調 function errorCallBack(error){ console.log(error) } ) } connect(); } </script> </body> </html>
在瀏覽器中打開這個HTML文件,而後打開控制檯,能夠看見,咱們已經鏈接服務端成功了:
鏈接成功以後呢,咱們就能夠嘗試在服務端向客戶端發送消息,先切換到ActiveMQ 的頁面:
能夠看見咱們的消費者的數量爲1了,而後點擊Send To,就能夠開始發消息了:
好比咱們發送一個「你好」,而後咱們再切到index.html:
咱們收到了來自服務端的問候~
消息已經可以實時接收了,如今就是須要把接收到的消息讀出來,思路很簡單,就是把語音合成相關API封裝成一個函數,而後當咱們服務端發送消息到客戶端以後,把消息數據傳到爲咱們定義好的語音播報函數裏面,而後就能讀出咱們服務端發出的消息了,說幹就幹:
//語音播報 speechInfo = () => { let speechInstance = new SpeechSynthesisUtterance(); return { //語音播報開始 start: function (content) { let lang = 'zh-CN'; let text = content; if( text !== '') { speechInstance.text = text; speechInstance.lang = lang; speechInstance.volume = 1; speechInstance.rate = 1; speechSynthesis.speak(speechInstance); speechInstance.onend = function(event){ console.log("語音播報完畢"); } } }, //暫停 pause : function () { speechSynthesis.pause(); }, //從新開始 resume: function() { speechSynthesis.resume(); }, //取消 cancel: function() { speechSynthesis.cancel(); } } };
那我們調用一下,而後在ActiceMQ頁面發送一條新消息,看是否是如咱們所願:
... client.subscribe('/topic/msg', function(message){ if(message.body){ data = message.body; console.log(message.body); //調用語音合成函數 speechInfo().start(data); } }) ...
若是是火狐,360安全瀏覽器等瀏覽器,咱們的消息和聲音都如期而至。
可是若是用的是Chrome的話,很難受,並無聲音,難道是Chrome不支持了嗎?可是咱們以前那兩行測試代碼說明Chrome是支持SpeechSynthesis
的,那是怎麼回事?答案就在下面:
Chrome再也不支持SpeechSynthesis.speak()
的自動播放,要想用的話,必須用戶手動去調用它。緣由能夠看這裏被垃圾廣告濫用後谷歌瀏覽器71將限制語音合成自動播放
垃圾網站出來背鍋!!!
想不到吧,有一天須要去「兼容」Chrome了。語音不能實時的播報出來,咱們看看有沒有什麼辦法。個人思路是在頁面加一個按鈕,而後進行模擬人去點擊,完整index.html
代碼:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div> <button id="btn"> 點擊</button> </div> <script src="http://cdn.bootcss.com/stomp.js/2.3.3/stomp.js"></script> <script> window.onload = function() { let data = ''; //創建鏈接 function connect(){ let client; let url = 'ws:127.0.0.1:61614/stomp'; client = Stomp.client(url); client.heartbeat.outgoing=0; client.connect({}, //鏈接成功回調 function connectCallback() { console.log("鏈接成功~"); //訂閱消息 client.subscribe('/topic/msg', function(message){ if(message.body){ data = message.body; console.log(message.body); if(navigator.userAgent.toLowerCase().indexOf("chrome") !== -1){ document.getElementById("btn").click(); } else { speechInfo().start(data); } } }) }, //鏈接失敗回調 function errorCallBack(error){ console.log(error) } ) } //語音播報 speechInfo = () => { let speechInstance = new SpeechSynthesisUtterance(); return { //語音播報開始 start: function (content) { let lang = 'zh-CN'; let text = content; if( text !== '') { speechInstance.text = text; speechInstance.lang = lang; speechInstance.volume = 1; speechInstance.rate = 1; speechSynthesis.speak(speechInstance); speechInstance.onend = function(event){ console.log("語音播報完畢"); } } }, //暫停 pause : function () { speechSynthesis.pause(); }, //從新開始 resume: function() { speechSynthesis.resume(); }, //取消 cancel: function() { speechSynthesis.cancel(); } } }; document.getElementById("btn").onclick=function () { console.log("觸發成功") speechInfo().start(data); }; document.getElementById("btn").click(); connect(); } </script> </body> </html>
可是咱們能想到,谷歌想不到?這裏又涉及一個知識點:isTrusted
Event接口的isTrusted是一個Boolean類型的只讀屬性.當事件由用戶操做生成時爲true,由腳本建立或修改,或經過調用EventTarget.dispatchEvent生成,爲false
咱們在控制檯代碼中打個斷點,而後在ActiveMQ 發條消息瞧一瞧,是否是與這個有關:
能夠看見isTrusted的值爲false,這個模擬點擊事件是不被瀏覽器信任的,而後咱們再手動點擊一下咱們寫好的按鈕:
isTrusted的值爲true,咱們的聲音也出來了,當咱們再在ActiveMQ 發送一條消息:
聲音自動播放出來了。
https://segmentfault.com/a/11...
https://www.cnblogs.com/golov...
https://www.jianshu.com/p/92d...
https://developer.mozilla.org...
須要提一點的是,我在實際是在react中開發的,相關方法都和上述的寫法相似,可是卻不會觸發Chrome對於SpeechSynthesis.speak()
的限制,這個限制也是我在寫這篇文章的時候,用原生js+HTML的時候發現的。總的來講用原生js+HTML實現的並不算完美,在Chrome下須要在頁面加載完成後進行一次點擊,才能把後續的語音實時的播報出來。若是你們有相關的解決辦法,或者用其它的方式實現了前端消息實時的語音播報,歡迎提出來,先謝過了~