本文主要用于解决业务场景中如何选择合适的方法进行数据交换( form , xhr, fetch, SSE, webstock, postmessage, web workers等)。并列举了一示些示例代码, 可能存在不全的地方欢迎大家补充。
本文用到的源代码都放在
关于 http协义基础可以参考一下 阮一峰老师的( 地址在文章最下方)
以下是正文—————————————-
前端经常使用的HTTP协议相关(1.0 / 1.1)
method
GET ( 对应 restful api 查询资源, 用于客户端从服务端取数据 )
POST(对应 restful api中的增加资源, 用于客户端传数据到服务端)
PUT (对应 restful api中的更新资源)
DELETE ( 对应 restful api中的删除资源 )
HEAD ( 可以用于http请求的时间什么,或者判断是否存在判断文件大小等)
OPTIONS (在前端中常用于 cors跨域验证)
TRACE * (我这边没有用到过,欢迎补充)
CONNECT * (我这边没有用到过,欢迎补充)
enctype
application/x-www-form-urlencoded (默认,正常的提交方式)
multipart/form-data(有上传文件时常用这种)
application/json ( ajax 常用这种格式)
text/xml
text/plain
enctype示例说明( form , ajax, fetch 三种示例 )
服务端 form_action.php
<?php
echo ‘<pre>’;
if($_POST){
echo “<h1>POST</h1>”;
print_r($_POST);
echo “<hr>”;
}
if(file_get_contents(“php://input”)){
echo “<h1>php://input</h1>”;
print_r(file_get_contents(“php://input”));
echo “<hr>”;
}
if($_FILES){
echo “<h1>file</h1>”;
print_r($_FILES);
echo “<hr>”;
}
* fetch api是基于Promise设计
* fetch 的一些例子 mdn/fetch-examples
服务器到客户端的推送 – Server-sent Events
这个是html5的一个新特性,主要用于服务器推送消息到客户端, 可以用于监控,通知,更新库存之类的应用场景, 在携程运动项目中我们主要应用于线上被预订后通知下发通知到场馆的操作界面上的即时改变状态。
图片来源于网络. 侵删
优点: 基于http协义无需特别的改造,调试方便, 可以CORS跨域
server-send events 是服务端往客户端单向推送的,如果客户端需要上传消息可以使用 WebSocket
客户端代码
var source = new EventSource(‘
source.on message = function(e) {
console.log(‘e’, JSON.parse( e.data));
document.getElementById(‘box’).innerHTML += “SSE notification: ” + e.data + ‘<br />’;
};
服务端代码
<?php
header(‘Content-Type: text/event-stream’);
header(‘Cache-Control: no-cache’);
//数据
$time = date(‘Y-m-d H:i:s’);
$data = array(
‘id’=>1,
‘name’=>’中文’,
‘time’=>$time
);
echo “data: “.json_encode($data).”\n\n”;
flush();
?>
echo “event: ping\n”; // 增加 event可以多送多个事件
js使用 source.addEventListener(‘ping’, function(){}, false); 来处理对应的事件
对于低版本的浏览器可以使用 eventsource polyfill
Yaffle/EventSource by yaffle
by Remy Sharp
rwaldron/jquery.eventsource by Rick Waldron
amvtek/EventSource by AmvTek
客户端与服务器双向通信 WebSocket
特点
1. websocket 是个双向的通信。
2. 常用于应用于一些都需要双方交互的,实时性比较强的地方(如聊天,在线客服)
3. 数据传输量小
4. websocket 是个 持久化的连接
原理图
图片来源于网络. 侵删
这个的服务端 是基于 nodejs实现的 (不要问为什么不是php, 因为 nodejs 简单些! )
server.js
var WebSocketServer = require(‘ws’).Server;
var wss = new WebSocketServer({port: 2000});
wss.on(‘connection’, function(ws) {
ws.send(‘服务端发来一条消息’);
ws.on(‘message’, function(message) {
//转发一下客户端发过来的消息
console.log(‘收到客户端来的消息: %s’, message);
ws.send(‘服务端收到来自客户端的消息:’ + message);
});
ws.on(‘close’, function(event) {
console.log(‘客户端请求关闭’,event);
});
});
client.html
<!DOCTYPE html>
<html>
<head>
<meta charset=”UTF-8″>
<title>WebSocket 双向通信</title>
<style>
#boxwarp > div{
border: 1px solid #ccc;
padding:10px;
margin:10px;
}
</style>
</head>
<body>
<button id=”btn”>发点什么</button>
<div id=”boxwarp”></div>
<script>
var ws = new WebSocket(“ws://127.0.0.1:2000/”);
document.getElementById(‘btn’).addEventListener(‘click’, function() {
ws.send(‘cancel_order’);
});
function addbox(msg){
var box = document.createElement(‘div’);
box.innerHTML = msg;
document.getElementById(‘boxwarp’).append(box);
}
ws.onopen = function() {
var msg = ‘ws已经联接’;
addbox(msg);
ws.send(msg);
};
ws.onmessage = function (evt) {
console.log(‘evt’);
addbox(evt.data);
};
ws.onclose = function() {
console.log(‘close’);
addbox(‘服务端关闭了ws’);
};
ws.onerror = function(err) {
addbox(err);
};
</script>
</body>
</html>
说完了 客户端与服客端之间的通信,现在我们来聊聊客户端之间的通信!
客户端与客户端页面之间的通信 postMessage
主要特点
1. window.postMessage() 方法可以安全地实现跨域通信
2.主要用于两个页面之间的消息传送
3. 可以使用 iframe 与window.open打开的页面进行通信.
特别的应用场景
我们的页面引用了其他的人页面,但我们不知道他们的页面高度,这时可以通过window.postMessages 从iframe 里面的页面来传到 当前页面.
语法
otherWindow.postMessage(message, targetOrigin, [transfer]);
示例代码
postmessage.html (入口)
<!DOCTYPE html>
<html>
<head>
<meta charset=”UTF-8″>
<title>postmessage示例</title>
<style>
html,body{height: 100%;}
*{padding: 0; margin:0;}
.warp{ display: flex; }
.warp > div,
.warp > iframe{
flex: 1;
margin:10px;
}
iframe{
height: 600px;
border: 1px solid #ccc;
}
</style>
</head>
<body>
<div>
<div>
左边页面
</div>
<div>
右边页面
</div>
</div>
<div>
<div class=”left warp”>
<iframe src=”./post1.html” frameborder=”0″ id=”post1″ name=”post1″></iframe>
</div>
<div class=”right warp”>
<iframe src=”./post2.html” frameborder=”0″ id=”post2″ name=”post2″></iframe>
</div>
<!– window.frames[0].postMessage(‘getcolor’,’ –>
</div>
<div>
<div><button id=”postBtn1″>向左边的(iframe)推送信息代码</button></div>
<div><button id=”postBtn2″>向右边的(iframe)推送信息代码</button></div>
</div>
<script>
document.getElementById(‘postBtn1’).addEventListener(‘click’, function(){
console.log(‘postBtn1’);
var date = new Date().toString();
window.post1.postMessage(date,’*’);
});
document.getElementById(‘postBtn2’).addEventListener(‘click’, function(){
console.log(‘postBtn2’);
var date = new Date().toString();
window.post2.postMessage(date,’*’);
});
window.addEventListener(‘message’,function(e){
if(e.data){
console.log(e.data);
console.log(e);
window.post1.postMessage(e.data,’*’);
}
},false);
</script>
</body>
</html>
post1.html
<!DOCTYPE html>
<html>
<head>
<meta charset=”UTF-8″>
<title>Document</title>
<style>
.sendbox{
background: #efefef;
margin-bottom: 10px;
}
</style>
</head>
<body>
<div>
<button id=”sendbox2″>直接发送到右边iframe</button>
左边的iframe
</div>
<div id=”box2″>
</div>
<script>
document.getElementById(‘sendbox2’).addEventListener(‘click’, function(){
window.parent.post2.postMessage(‘收到来自左边ifarme的消息’ + +new Date(),’*’);
});
function addbox(html){
var item = document.createElement(‘div’);
item.innerHTML = html;
document.getElementById(‘box2’).append(item);
}
window.addEventListener(‘message’,function(e){
if(e.data){
addbox(e.data);
}
},false);
</script>
</body>
</html>
post2.html
<!DOCTYPE html>
<html>
<head>
<meta charset=”UTF-8″>
<title>Document</title>
<style>
.sendbox{
background: #ccc;
margin-bottom: 10px;
}
</style>
</head>
<body>
<div style=”text-align: right;”>
<button id=”sendbox”>中转到左边</button>
<button id=”sendbox2″>直接到左边</button>
右边的iframe
</div>
<div id=”box”></div>
<script>
document.getElementById(‘sendbox’).addEventListener(‘click’, function(){
/*- 向父级页面传 -*/
window.parent.postMessage(‘来自post2的消息’ + +new Date(),’*’);
});
document.getElementById(‘sendbox2’).addEventListener(‘click’, function(){
window.parent.post1.postMessage(‘直接来自右边’ + +new Date(),’*’);
});
function addbox(html){
var item = document.createElement(‘div’);
item.innerHTML = html;
document.getElementById(‘box’).append(item);
}
window.addEventListener(‘message’,function(e){
if(e.data){
addbox(e.data);
}
},false);
</script>
</body>
</html>
Web Workers 进程通信(html5中的js的后台进程)
javascript设计上是一个单线,也就是说在执行js过程中只能执行一个任务, 其他的任务都在队列中等待运行。
如果我们执行大量计算的任务时,就会阻止浏览器执行js,导致浏览器假死。
html5的 web Workers 子进程 就是为了解决这种问题而设计的。把大量计算的任务当作类似ajax异步方式进入子进程计算,计算完了再通过 postmessage通知主进程计算结果.
图片来源于网络. 侵删
主线程代码(index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset=”UTF-8″>
<title>Document</title>
<style>
.box-warp > div{
border: 1px solid #ccc;
margin:10px;
padding:10px;
}
</style>
</head>
<body>
<button id=”btn”>开启一个后台线程(点击外框中止线程)</button>
<div id=”boxwarp”></div>
<script>
var id = 1;
function init_works(){
var warpid = ‘box’+id;
var box = document.createElement(‘div’);
box.id = warpid;
document.getElementById(‘boxwarp’).append(box);
var worker = new Worker(‘./compute.js’);
//监听后台进程发过来的消息
worker.onmessage= function (event) {
// 把子线程返回的结果添加到 div 上
document.getElementById(warpid).innerHTML += event.data+”<br/>”;
};
//点击中止后端进程
box.addEventListener(‘click’, function(){
worker.postMessage(“oh, 我被干掉了” + warpid);
var time = setTimeout(function(){
worker.terminate();
clearTimeout(time);
},0);
});
//往后台线程发送消息
worker.postMessage(“hi, 我是” + warpid);
id++;
}
document.getElementById(‘btn’).addEventListener(‘click’, function(){
init_works();
});
</script>
</body>
</html>
后台进程代码( compute.js )
var i=0;
function timeX(){
i++;
postMessage(i);
if(i>9){
postMessage(‘no 我不想动了’);
close(); //中止线程
}
setTimeout(function(){
timeX();
},1000);
}
timeX();
//收到主线程的消息
onmessage = function (oEvent) {
postMessage(oEvent.data);
};
上述代码简单的说明一下, 主进程与后台进程之间的互相通信.
广告 : 最近忙的项目【携程运动】上线拉!!!.
HTTP 协议入门 – 阮一峰的网络日志