這篇文章主要講解了“怎么實現可插拔的跨域聊天機器人”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“怎么實現可插拔的跨域聊天機器人”吧!
你將學到
跨域技術常用方案介紹
postMessage實現跨域通信
如何實現聊天機器人
node搭建本地服務器來實現渲染頁面和跨域
回答語料庫設計思路
效果預覽
正文
1. 跨域技術常用方案介紹
首先要強調的是跨域的安全限制都是對瀏覽器端來說的,服務器端是不存在跨域安全限制的。我們常用的跨域技術主要有如下幾種:
JSONP跨域
iframe+domain跨域
nginx反向代理跨域
cors跨域
postMessage跨域
JSONP實現跨域請求的原理就是動態創建script標簽,然后利用script的src 不受同源策略約束來跨域獲取數據。JSONP 主要由回調函數和數據兩部分組成?;卣{函數的名字一般是在請求中指定的。而數據就是傳入回調函數中的 JSON 數據。我們一般可以在全局定義一個回調函數,然后在script標簽里傳入回調函數即可:
window.handleData = function(data){ // ... } let script = document.createElement("script"); script.src = "https://xxxx.com/v0/search?q=xuxi&callback=handleData"; document.body.insertBefore(script, document.body.firstChild);
這樣我們就能在回調函數handleData中拿到服務器接口返回的數據了。
雖然jsonp實現跨域方式很簡單,但是只支持get請求,對傳輸的數據量有一定限制。cors跨域是目前我們用的比較多的本地調試方式,原理就是在服務端設置響應頭header的Access-Control-Allow-Origin字段,這樣瀏覽器檢測到header中的Access-Control-Allow-Origin,這樣就可以跨域了。
至于我們設置了cors之后在network中出現了兩次請求的問題,其實涉及到cors跨域的請求預檢,分為簡單請求和非簡單請求兩種,這塊知識可以單獨抽離出一篇文章,感興趣的可以自己學習了解一下。
2. postMessage實現跨域通信
window.postMessage() 方法可以安全地實現跨源通信。通常,對于兩個不同頁面的腳本,只有當執行它們的頁面位于具有相同的協議,端口號以及主機 (兩個頁面的模數 Document.domain設置為相同的值) 時,這兩個腳本才能相互通信。window.postMessage() 方法提供了一種受控機制來規避此限制,只要正確的使用,這種方法就很安全。
本質上說postMessage()是基于消息事件機制來實現跨域通信,它隸屬于消息窗體本身,比如window以及window內嵌的frame的window,基本使用形式如下:
someWindow.postMessage(message, targetOrigin, [transfer]);
參數介紹:
someWindow 窗口的一個引用,比如iframe的contentWindow屬性、執行window.open返回的窗口對象、或者是命名過或數值索引的window.frames
message 將要發送到其他 window的數據。意味著你可以不受什么限制的將數據對象安全的傳送給目標窗口而無需自己序列化
targetOrigin 通過窗口的origin屬性來指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示無限制)。不提供確切的目標將導致數據泄露等安全問題
transfer 是一串和message 同時傳遞的 Transferable 對象. 這些對象的所有權將被轉移給消息的接收方,而發送一方將不再保有所有權
我們可以通過如下方式來監聽message:
window.addEventListener("message", receiveMessage, false); function receiveMessage(event){ let origin = event.origin || event.originalEvent.origin; if (origin !== "http://aaa:8080") return; // ... console.log(event.data) } // 派發消息的頁面 winB.postMessage(_({text: '休息休息'}), origin)
我們的event里有如下幾個核心的屬性:
data 從其他 window 中傳遞過來的對象
origin 調用 postMessage 時消息發送方窗口的 origin . 這個字符串由 協議、“://“、域名、“ : 端口號”拼接而成
source 對發送消息的窗口對象的引用; 您可以使用此來在具有不同origin的兩個窗口之間建立雙向通信
3. 實現聊天機器人
在熟悉以上知識點之后,我們開始來寫我們聊天機器人的demo。首先我們寫兩個html,分別為a.html和b.html,然后用node分別代理兩個不同頁面,設置不同端口:
// a.js //依賴一個http模塊,相當于java中的import,與C#中的using var http = require('http'); var fs = require('fs'); var { resolve } = require('path'); //創建一個服務器對象 server = http.createServer(function (req, res) { //設置請求成功時響應頭部的MIME為純文本 res.writeHeader(200, {"Content-Type": "text/html"}); //向客戶端輸出字符 let data = fs.readFileSync(resolve(__dirname, './a.html')) res.end(data); }); //讓服務器監聽本地8000端口開始運行 server.listen(8000,'127.0.0.1'); console.log('http://127.0.0.1:8000') // b.js // ... server.listen(8001,'127.0.0.1');
由上可知我們a.html代理在8000端口下,b.html代理在8001端口下,由瀏覽器的同源策略可知他們存在跨域問題。
跨域實現之后我們可以開始搭建頁面層級了,我們這里將b頁面以iframe的形式嵌入到a頁面,具體結構如下:
這樣我們就可以愉快的搭建postMessage體系了。首先我們在a頁面通過發送按鈕和輸入框將消息發送給b頁面,大致結構如下:
<body> <div class="wrap"> <iframe src="http://127.0.0.1:8001" frameborder="0" id="b"></iframe> <div class="control"> <input type="text" placeholder="請輸入內容" id="ipt"> <span id="send">發送</span> </div> </div> <script> window.onload = function() { let origin = 'http://127.0.0.1:8001'; let _ = (data) => JSON.stringify(data); let winB = document.querySelector('#b').contentWindow; let sendBtn = document.querySelector('#send'); sendBtn.addEventListener('click', (e) => { let text = document.querySelector('#ipt'); winB.postMessage(_({text: text.value}), origin) text.value = ''; }, false) winB.postMessage(_({text: ''}), origin) } </script> </body>
我們可以通過iframe的contentWindow來拿到b頁面窗體的引用,然后在發送按鈕的點擊事件中觸發postMessage將數據發送給B。B頁面結構如下:
<body> <div class="content"> <h5>Lab智能機器人</h5> <div class="content-inner"></div> </div> <script> // 語料庫 const pool = []; window.addEventListener("message", receiveMessage, false); let content = document.querySelector('.content-inner'); let initContentH = content.scrollHeight; let _ = (data) => JSON.stringify(data); function createChat(type, mes) { let dialog = document.createElement('div'); dialog.className = type === 0 ? 'dialog robot' : 'dialog user'; let content = type === 0 ? ` <span class="tx">${type === 0 ? 'lab' : 'user'}</span> <span class="mes">${mes}</span> ` : ` <span class="mes">${mes}</span> <span class="tx">${type === 0 ? 'lab' : 'user'}</span> `; dialog.innerHTML = content; return dialog } function scrollTop(el, h) { if(el.scrollHeight !== h) { el.scrollTop = h + 100; } } function receiveMessage(event){ // 兼容其他瀏覽器 let origin = event.origin || event.originalEvent.origin; if(origin === 'http://127.0.0.1:8000') { let data = JSON.parse(event.data); if(data && !data.text) { mes = { text: '你好,我是機器人Lab,請問有什么可以幫到您的嗎?' }; event.source.postMessage(_(mes), event.origin) content.appendChild(createChat(0, mes.text)) }else { content.appendChild(createChat(1, data.text)) scrollTop(content, initContentH) setTimeout(() => { content.appendChild(createChat(0, '正在解決')) scrollTop(content, initContentH) }, 2000); } } } </script> </body>
我們在b頁面中去解析a頁面的數據并做出相應的回答。這樣,我們的基本聊天機器人就實現了。
4. 回答語料庫設計思路
至于當我們在a頁面發送了一個消息,b頁面如何解析并回答,可以有如下幾種思路:
通過后端接口實現,即我們可以將a的數據作為參數傳遞給某個后端接口,讓后端來實現返回需要的數據,這種在AI機器人中應用的很廣泛。
純前端實現。前端定義回答的語料庫,通過關鍵詞匹配來拿到實現應答,這種一般用于普通的預設問題的回答。
5.實現可插拔式
可插拔式就是一個頁面可以放在不同平臺使用。這種我們可以設置origin白名單,只需要將b頁面封裝,其他系統可以使用類于a頁面的方式,只提供發送信息的接口,這樣我們就可以在不同平使用了。
感謝各位的閱讀,以上就是“怎么實現可插拔的跨域聊天機器人”的內容了,經過本文的學習后,相信大家對怎么實現可插拔的跨域聊天機器人這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。