websocket原理與聊天功能
阿新 • • 發佈:2018-12-18
前段時間剛好要做一個小型的網頁版聊天室,需求是用電腦完成語音通話(前面部落格有),傳送圖片/文字/檔案什麼的。這就涉及到的網頁套接字,在這裡就不得不說一下的的WebSocket的原理
首先,可將網頁套接字是HTML5出的東西(協議),也可以理解的WebSocket的是一個新協議,跟HTTP協議基本沒有關係,只是HTTP只是一種短暫的臨時的非持久的協議,網頁套接字的就是一個持久化的協議;
舉個例子:聊天室的時候,你發訊息給別人的時候,你可以通過一個事件去告訴伺服器:我發了一條資訊給XXX;那你在等別人回訊息的時候,那你就要問伺服器:有沒有我的資訊伺服器:沒有....然後要問幾次伺服器,可能別人才會把訊息傳給伺服器,最後你訪問伺服器的時候,伺服器才會告訴你資訊這就要求你要不停的去訪問伺服器。
程式碼如下:
<script> // WebSocket var websocket = null;var message_arr=[];var isFire=true;var duration = 0; //判斷當前瀏覽器是否支援WebSocket if ('WebSocket' in window) { //websocket = new WebSocket("ws://218.77.104.15:8888"); //ws://192.168.8.56:1234 websocket = new WebSocket("ws://192.168.8.56:1234"); //ws://192.168.8.56:1234 } else { alert('當前瀏覽器不支援websocket,請使用最新的瀏覽器'); } //連線發生錯誤的回撥方法 websocket.onerror = function() { setMessageInnerHTML("WebSocket連線發生錯誤"); }; //連線成功建立的回撥方法 websocket.onopen = function() { var uid={"tel":sessionStorage.getItem('uname'),"client":"1"}; websocket.send(JSON.stringify(uid)); }; //接收到訊息的回撥方法 websocket.onmessage = function(event) { console.log('接收到訊息的回撥方法'); console.log(event); //聊天 JSON.parse(event.data).code=='s_ok'?console.log("連線成功"):''; //發生火災的時候 if(JSON.parse(event.data).code!='s_ok'){ setMessageInnerHTML(JSON.parse(event.data)); } }; //連線關閉的回撥方法 websocket.onclose = function() { }; //監聽視窗關閉事件,當視窗關閉時,主動去關閉websocket連線,防止連線還沒斷開就關閉視窗,server端會拋異常。 window.onbeforeunload = function() { closeWebSocket(); }; //將訊息顯示在網頁上 function setMessageInnerHTML(data) { if (data.type=="fire") { layer.confirm("<div style='padding:15px;font-weight: bold;'>" + data.happen_time + " " + data.region_name + "發生火災,請立即派人前往滅火!</div>", { btn: ['檢視詳情','取消'],skin: 'layui-layer-molv' ,closeBtn: 0,anim: 4,btnAlign: 'c',title:'警告' }, function(){ localStorage.setItem("index_xq",0); localStorage.setItem("fireId_xq",data.percent); $("#index_main_context").load("lqz_fire_details.html"); $("#index_titel").html("火情上報詳情"); layer.closeAll(); }, function(){ }); var myVideo = document.getElementById("audio"); myVideo.play(); }else if (data.type=="mail") { tz(); } if(data.type=='chat'){ message(data.msg_from_uid,data.msg_from_name,data.msg_from_tel); layer.title('與'+data.msg_from_name+'聊天中',0); if (data.msg_type=="3") { $("#record").append("<li style='margin: 10px 0;'>"+data.msg_from_name+":<audio src='"+Public_address+"uploads/"+data.message+"' controls=''></li>"); }else if (data.msg_type=="2"){ $("#record").append("<li style='margin: 10px 0;'>"+data.msg_from_name+":<img src='"+Public_address+"uploads/"+data.message+"' width='100px' class='img_yl'/></li>"); }else{ $("#record").append("<li style='margin: 10px 0;'>"+data.msg_from_name+":<span>"+data.message +"</span></li>"); } $("#record").animate({scrollTop:"3000px"}, 50); } } // 錄製 $(document).on('click','#start',function() { $(this).css("color","#addc9d"); var audio = document.querySelectorAll('audio'); for(var i = 0; i < audio.length; i++){ if(!audio[i].paused){ audio[i].pause(); } } $('#js_record_time').html("錄音時間:0秒"); //開始錄音時計時器開始計時 timer = setInterval(function(){ duration++; $('#js_record_time').html("錄音時間:"+duration+"秒"); return duration },1000); $(".btn_s").css("visibility","visible"); recorder.start(); }); // 傳送 $(document).on('click','#stop',function() { clearInterval(timer);//清除錄音計時器 $("#start").css("color","#000"); $(".btn_s").css("visibility","hidden"); $('#js_record_time').html(''); recorder.stop(); recorder.getBlob(function(blob){ var audio = document.createElement('audio'); audio.src = URL.createObjectURL(blob); audio.controls = true; $("#record").append("<li class='name'><audio src='"+URL.createObjectURL(blob)+"' controls=''></audio>:我</li>"); var formData = new FormData(); formData.append('chatFile',blob, Date.parse(new Date())+".mp3"); formData.append('msg_type',3); formData.append('msg_to_uid',$(".message_left .on").attr('data-name')); formData.append('msg_from_headimage',sessionStorage.getItem("imageHead")); formData.append('msg_from_name',sessionStorage.getItem("name")); formData.append('msg_tiem',getNowFormatDate()); formData.append('msg_from_uid',sessionStorage.getItem("s_uid")); formData.append('msg_from_tel',sessionStorage.getItem("uname")); formData.append('msg_to_tel',$(".message_left .on").attr('data-tel')); formData.append('voice_time',String(duration*1000)); var s_token = sessionStorage.getItem("s_token"); $.ajax({ type: 'POST', url: Public_address+"fire/user/chat"+'?s_token='+s_token, data: formData, processData: false, contentType: false, dataType: 'json', cache: false, success: function (json){ duration = 0; $("#record").animate({scrollTop:"3000px"}, 50); }, error: function (jqXHR, textStatus, errorThrown){ alert('Error! '+ textStatus + ' - ' + errorThrown + '\n\n' + jqXHR.responseText); } }); }); }); // 取消 $(document).on('click','#cancel',function() { clearInterval(timer);//清除錄音計時器 duration = 0; $("#start").css("color","#000"); $(".btn_s").css("visibility","hidden"); $('#js_record_time').html(''); recorder.stop(); }); // 傳送圖片 $(document).on('change','#photoName2',function() { var file = document.getElementById("photoName2"); var blob = file.files[0]; // 獲取的圖片檔案 console.log('1'); if(window.createObjectURL != undefined){ $("#record").append("<li class='name'><img src='"+window.createObjectURL(blob)+"' width='100px' class='img_yl'/></audio>:我</li>"); }else if(window.URL != undefined){ $("#record").append("<li class='name'><img src='"+window.URL.createObjectURL(blob)+"' width='100px' class='img_yl'/></audio>:我</li>"); }else if(window.webkitUrl != undefined){ $("#record").append("<li class='name'><img src='"+window.webkitUrl.createObjectURL(blob)+"' width='100px' class='img_yl'/></audio>:我</li>"); } var formData = new FormData(); formData.append('chatFile',blob); formData.append('msg_type',2); formData.append('msg_to_uid',$(".message_left .on").attr('data-name')); formData.append('msg_from_headimage',sessionStorage.getItem("imageHead")); formData.append('msg_from_name',sessionStorage.getItem("name")); formData.append('msg_tiem',getNowFormatDate()); formData.append('msg_from_uid',sessionStorage.getItem("s_uid")); formData.append('msg_from_tel',sessionStorage.getItem("uname")); formData.append('msg_to_tel',$(".message_left .on").attr('data-tel')); formData.append('voice_time',''); var s_token = sessionStorage.getItem("s_token"); $.ajax({ type: 'POST', url: Public_address+"fire/user/chat"+'?s_token='+s_token, data: formData, processData: false, contentType: false, dataType: 'json', cache: false, success: function (json){ $("#record").animate({scrollTop:"3000px"}, 50); //因為事件是change,傳圖片結束以後把#photoName2清空掉 $('#photoName2').val(''); }, error: function (jqXHR, textStatus, errorThrown){ alert('Error! '+ textStatus + ' - ' + errorThrown + '\n\n' + jqXHR.responseText); } }); }); // 預覽圖片 $(document).on( "click", ".img_yl",function(event) { var src=$(this).attr("src"); var $h1="<img src=\"" +src+ "\" style='height:100%'>"; layer.open({ skin: 'layui-layer-molv', title:'圖片預覽', type: 1, area: ['570px', '480px;'], shadeClose: true, btnAlign: 'c', tipsMore : true, zIndex : layer.zIndex, content:$h1 }); }); // 回車鍵傳送事件 $(document).keypress(function(e) { if(e.which == 13) { e.cancelBubble=true; e.preventDefault(); e.stopPropagation(); var content=$("#content").val(); if (content!='') { sendAjax({ "url":"fire/user/chat", "data":{"msg_to_uid":sessionStorage.getItem("message_name"),"message":content,"msg_type":1,"msg_from_headimage":sessionStorage.getItem("imageHead"),"msg_from_name":sessionStorage.getItem("name"),"msg_tiem":getNowFormatDate(),"msg_from_uid":sessionStorage.getItem("s_uid"),"msg_from_tel":sessionStorage.getItem("uname"),"msg_to_tel":$(".message_left .on").attr('data-tel'),"voice_time":''},"callback":function(data){ if (data.code=='s_ok') { $("#record").append("<li class='name'><span>"+content+"</span>:我</li>"); $("#record").animate({scrollTop:"3000px"}, 50); if (data.var==0) { $("#record").append("<p style='text-align:center;font-size: 12px;'>對方不線上</p>"); } } $("#content").val(''); } }) } } }); $(document).on("click",".message_left p",function(){ var index = $(this).index(); $(this).addClass("on").siblings().removeClass("on"); var this_title=$(this).html(); layer.title('與'+this_title+'聊天中',0); // message($(this).attr('data-name'),this_title); var content=$("#content").val(); if (content!='') { sendAjax({ "url":"fire/user/chat", "data":{"msg_to_uid":$(this).attr('data-name'),"message":content,"msg_type":1},"callback":function(data){ if (data.code=='s_ok') { $("#record").append("<li class='name'><span>"+content+"</span>:我</li>"); $("#record").animate({scrollTop:"3000px"}, 50); if (data.var==0) { $("#record").append("<p style='text-align:center;font-size: 12px;'>對方不線上</p>"); } } $("#content").val(''); } }) } }); function message(name,phone,tel) { if (isFire) { isFire=false; start = document.querySelector('#start'); stop = document.querySelector('#stop'); recorder = new Recorder({ sampleRate: 44100, //取樣頻率,預設為44100Hz(標準MP3取樣率) bitRate: 128, //位元率,預設為128kbps(標準MP3質量) success: function(){ //成功回撥函式 // start.disabled = false; }, error: function(msg){ //失敗回撥函式 alert(msg); }, fix: function(msg){ //不支援H5錄音回撥函式 alert(msg); } }); } sessionStorage.setItem("message_name",name); if($.inArray(name, message_arr)<0){ if($(".message_left").length==0){ layer.confirm(`<div class='message_left'></div> <div class='message_right'> <ul id='record'></ul> <ul class='msg_type'> <li id='picture' onclick="$('#photoName2').click()"><i class='icon-picture'></i></li> <li style='display:none'><input type="file" id="photoName2" accept="image/png,image/jpg,image/gif,image/JPEG"/></li> <li id='start' title='錄音'><i class='icon-play'></i></li> <li><span id='js_record_time'></span></li> <li class='btn_s' id='stop' title='傳送'>傳送</li> <li class='btn_s btn_s2' id='cancel' title='取消'>取消</li> </ul> <textarea id='content' maxlength='1024'></textarea> </div>`, { btn: ['傳送','取消'], skin: 'layui-layer-molv', btnAlign: 'c', shade:0, area: ['700px','500px'], zIndex : layer.zIndex, cancel: function(){message_arr=[];} }, function(){ var content=$("#content").val(); if (content!='') { sendAjax({ "url":"fire/user/chat", "data":{"msg_to_uid":sessionStorage.getItem("message_name"),"message":content,"msg_type":1,"msg_from_headimage":sessionStorage.getItem("imageHead"),"msg_from_name":sessionStorage.getItem("name"),"msg_tiem":getNowFormatDate(),"msg_from_uid":sessionStorage.getItem("s_uid"),"msg_from_tel":sessionStorage.getItem("uname"),"msg_to_tel":$(".message_left .on").attr('data-tel'),"voice_time":''},"callback":function(data){ if (data.code=='s_ok') { $("#record").append("<li class='name'><span>"+content+"</span>:我</li>"); $("#record").animate({scrollTop:"3000px"}, 50); if (data.var==0) { $("#record").append("<p style='text-align:center;font-size: 12px;'>對方不線上</p>"); } } $("#content").val(''); } }) } }, function(){ message_arr=[]; }); }; $(".message_left p").removeClass("on"); $(".message_left").append("<p class='on' data-name="+name+" data-tel="+tel+">"+phone+"</p>"); layer.title('與'+phone+'聊天中',0);$(".message_left").animate({scrollTop:"3000px"}, 50); $("#record").html(""); findChatngo(name,tel); // 聊天記錄 function findChatngo(uid,tel){ sendAjax({ "url":"fire/user/getUserChatRecord", "data":{"uid":uid},"callback":function(data){ if (data.code=="s_ok") { var result=data.var; for (var i = 0; i < result.length; i++) { if (tel==result[i].msg_to_tel) { if (result[i].msg_type=="3") { $("#record").append("<li class='name'><audio src='"+Public_address+"uploads/"+result[i].message+"' controls=''></audio>:我</li>"); }else if (result[i].msg_type=="2"){ $("#record").append("<li class='name'><img src='"+Public_address+"uploads/"+result[i].message+"' width='100px' class='img_yl'/>:我</li>"); }else{ $("#record").append("<li class='name'><span>"+result[i].message +"</span>:我</li>"); } }else{ if (result[i].msg_type=="3") { $("#record").append("<li style='margin: 10px 0;'>"+result[i].msg_from_name+":<audio src='"+Public_address+"uploads/"+result[i].message+"' controls=''></li>"); }else if (result[i].msg_type=="2"){ $("#record").append("<li style='margin: 10px 0;'>"+result[i].msg_from_name+":<img src='"+Public_address+"uploads/"+result[i].message+"' width='100px' class='img_yl'/></li>"); }else{ $("#record").append("<li style='margin: 10px 0;'>"+result[i].msg_from_name+":<span>"+result[i].message +"</span></li>"); } } } $("#record").animate({scrollTop:"3000px"}, 50); } }, error:function(e){ layer.msg("錯誤!!"); } }); }; }else{ $(".message_left p").removeClass("on"); var leftp=$(".message_left p"); for (var i = 0; i < leftp.length; i++) { if($(leftp[i]).attr("data-name")==name){ $(leftp[i]).addClass("on"); } } layer.title(phone,0); } $(".layui-layer-content").css({"min-height":"419px","overflow":"hidden"}); message_arr.push(name); }; </script>
效果如下