HTTP 2.0 服务器推送技术的创新 已翻译 100%

oschina 投递于 2013/06/14 11:42 (共 7 段, 翻译完成于 06-17)
阅读 11384
收藏 204
10
加载中

HTTP 2.0 允许服务器为一次客户端请求发送多个响应(并行的) - 即, 服务器推送。等等,我们为什么想要这样? 是这样的,一个一般的网页需要一堆的额外资源,比如JavaScript,CSS,和图片, 对这些资源的引用就内置在服务器产生的HTML页面里。那么,与其等待客户端去发现对这些资源的引用,为什么不让服务器立即把这些资源都发送过去呢?服务器推送可以消除这种不必要的网络等待所带来的整个往返耗时。

事实上,如果你曾经内联的引用过一个资源(CSS, JS,或者一个图片),那么你已经“模拟”过服务器推送:一个内联资源被作为父文档的一部分“推送”过来。唯一的不同是HTTP 2.0使得这一模式更有效而且更强大!

lwei
lwei
翻译于 2013/06/14 14:35
1

着手进行HTTP 2.0服务器推送

一个内联的资源,从定义上说,是父文档的一部分。那么,它就不能被独立的缓存,并且它需要在许多不同的页面之间被复制 - 这是很低效的。相反的,推送的资源可以被浏览器独立的缓存起来,从而在许多页面中复用。这里准备了一个例子:

spdy.createServer(options, function(req, res) {
  // push JavaScript asset (/main.js) to the client
  res.push('/main.js', {'content-type': 'application/javascript'}, function(err, stream) {
    stream.end('alert("hello from push stream!")');
  });

  // write main response body and terminate stream
  res.end('Hello World! <script src="/main.js"></script>');
}).listen(443);

上例中,我们有一个借助于node-spdy module实现的最简SPDY服务,它对所有的入站请求的响应是,输出一个字符串"Hello World!",跟着是一个脚本标记。除此之外,我们还做了些聪明的事情: 我们推送“main.js”文件到客户端,该文件触发了一个JavaScript弹出框。

结果是,当浏览器发现HTML响应中的脚本标记时,“main.js”文件已经在缓存中了,不会发生额外的网络往返!HTTP 2.0 服务器推送 废弃了内联引用。最重要的是,服务器推送已经被所有的支持SPDY的浏览器所支持(Firefox,Opera,和Chrome)。

lwei
lwei
翻译于 2013/06/14 15:31
1

我们还能推送什么?

用服务器推送替换内嵌资源是一个典型例子。但是,为什么止步于此,我们还能推送什么? 其实, 任何HTTP响应都是平等的游戏。我们能推送一次重定向吗? 是的, 那很简单:

spdy.createServer(options, function(req, res) {
  //push JavaScript asset (/newasset.js) to the client
  res.push('/newasset.js', {'content-type': 'application/javascript'}, function(err, stream) {
    stream.end('alert("hello from (redirected) push stream!")');
  });

  // push 301 redirect: /asset.js -> /newasset.js
  res.push('/asset.js', {':status': 301, 'Location': '/newasset.js'}, function(err, stream) {
    stream.end('301 Redirect');
  });

  // write main response body and terminate stream
  res.end('<script src="/asset.js"></script>');
}).listen(443);

跟上面的例子一样,只不过我们已经把“asset.js”资源替换为一次对“newasset.js”文件的301重定向。浏览器对重定向和“asset.js”都进行了缓存,并且在无任何额外网络往返的情况下执行脚本。怎么应用?我把这个问题留给读者当练习吧。

lwei
lwei
翻译于 2013/06/14 15:47
2

我们还能做的更多吗?推送缓存失效信息和再验证信息到客户端,怎么样?我们可以把已经存在于客户端缓存中的任何资源标记为失效(即推送一个失效时间戳),或者相反,推送一个携带未来时间戳的304来更新资源的生存期。简言之,服务器能够主动的管理客户端缓存!

如果服务器过于激进或者不守规则,那么客户端可以限制推送流的数量,或者只要它愿意它可以取消某一个流。找出合适的策略并在两端之间作出平衡,是找出服务器推送最佳实践的关键 - 这不是一项轻松的挑战,但却能带来很高回报。

注: 目前的浏览器不支持推送缓存再验证。应该支持吗?

lwei
lwei
翻译于 2013/06/14 16:28
1

服务器推送的客户端通知

HTTP 2.0服务器推送不是诸如Server-Sent Events (SSE)或WebSocket的技术替代品。通过HTTP 2.0服务器推送传递过来的资源由浏览器来处理,但却不能上升到程序代码的层面 - 因为没有JavaScript API来获取这些事件的通知。不过,解决这个难题的方法却很简单,因为我们可以把一个SSE通道和服务器推送结合起来,使两者都达到最佳效果:

spdy.createServer(options, function(req, res) {
  // set content type for SSE stream
  res.setHeader('Content-Type', 'text/event-stream');

  messageId = 1;
  setInterval(function(){
    // push a simple JSON message into client's cache
    var msg = JSON.stringify({'msg': messageId});
    var resourcePath = '/resource/'+messageId;
    res.push(resourcePath, {}, function(err, stream) { stream.end(msg) });

    // notify client that resource is available in cache
    res.write('data:'+resourcePath+'\n\n');
    messageId+=1;
  }, 2000);
}).listen(443);
lwei
lwei
翻译于 2013/06/14 17:16
1
诚然,下面这个例子有点儿傻,但却很能说明问题: 服务器每隔两秒钟产生一条消息,并把它推送到客户端的缓存里,然后发送一个SSE通知到客户端。另一方面,客户端在应用程序代码中订阅这些事件,并执行自己的逻辑来处理这些事件:
<script>
  var source = new EventSource('/');

  source.onmessage = function(e) {
    document.body.innerHTML += "SSE notification: " + e.data + '<br />';

    // fetch resource via XHR... from cache!
    var xhr = new XMLHttpRequest();
    xhr.open('GET', e.data);
    xhr.onload = function() {
      document.body.innerHTML += "Message: " + this.response + '<br />';
    };

    xhr.send();
  };
</script>

长效的SSE流,被推送的资源,和其它所有HTTP 2.0流都有效的复用了同一个TCP链接 - 没有额外的链接开销和不必要的网络往返。通过把SSE和服务器推送结合起来,我们可以传送任意资源(二进制或文本)到客户端,利用浏览器本地缓存带来的好处,并执行恰当的应用逻辑! 最重要的是,今天这已经成为可能。

lwei
lwei
翻译于 2013/06/17 10:03
1

服务器推送创新

服务器推送开启了一个充满了优化机会的全新世界。我们上面所举的例子只是展示了冰山一角,仍有许多其他问题需要考虑:

  • 什么资源应当被推送? 何时被推送?它们是否已经在缓存中?
  • 服务器能够自动推断应当推送哪些资源吗?
  • 是否应当支持诸如主动缓存管理之类的高级应用?
  • 我们应当怎样设计我们的应用,才能从服务器推送中获益最多?
  • ...

通过HTTP 2.0,服务器有机会变得非常非常智能,包括如何优化传送一些具体的资源,更重要的是,也包括优化对整个应用的传送。类似的,浏览器可能增加额外的API和能力来使这个过程更加高效。事实上,长期来看,服务器推送很可能会成为HTTP 2.0的杀手级特性!

lwei
lwei
翻译于 2013/06/17 10:25
2
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(32)

jkant
jkant
不知道你们试过没有。
”服务器推送的客户端通知“ 这个实现之后,关闭浏览器后端就会断掉?
我是使用node.js实现的后端。推送和接收消息都正常。
但是一旦关闭某一个浏览页就会报错。
Error: Sending illegal frame (PUSH_PROMISE) in CLOSED state.
X
Xiqincai
我喜欢代码简洁易读,服务稳定的推送服务,前段时间研究了一下goeasy,后台推送只需要两行代码, js前端推送也只需要3,4行,而且文档齐全,还提供了后台查询信息收发情况,所以我觉得GoEasy推送服务是个不错的选择。
快速入门:goeasy.io/www/started.jsp
GoEasy web实时推送官网:https://goeasy.io
1. 引入goeasy.js
2. 客户端订阅,
Var goeasy = new GoEasy({appkey:’your appkey’});
goeasy.subscribe(channel:”your channel”, onMessage:function(message){alert(‘received message’+ message.content)})
3. 三种推送方式
Javascript: goeasy.publish({channel:’your channel’, message:’your publish msg’});
Java SDK: GoEasy goeasy = new GoEasy(“appkey”); goeasy.publish(“your channel”,”your msg”);
RestAPI: https://goeasy.io/goeasy/publish
三步轻松实现web推送及接收。
我土鳖

引用来自“江振宇”的评论

引用来自“sunfc”的评论

引用来自“江振宇”的评论

这个不跟websocket打架了吗?

websocket 用来传输消息 这个可以推送资源文件

websocket也能传二进制数据,可能没法对应成http里面的文件。

浏览器不会缓存websocket中的数据。
江振宇
江振宇

引用来自“sunfc”的评论

引用来自“江振宇”的评论

这个不跟websocket打架了吗?

websocket 用来传输消息 这个可以推送资源文件

websocket也能传二进制数据,可能没法对应成http里面的文件。
s
sunfc

引用来自“江振宇”的评论

这个不跟websocket打架了吗?

websocket 用来传输消息 这个可以推送资源文件
鲨鱼哥
鲨鱼哥
http是无状态的,客户端请求完成后就和服务器断开了tcp连接了。如果服务器不和客户端保持tcp连接的话,服务器怎么知道往哪个客户端推啊?
blindcat
blindcat
是不是这样:浏览器请求一次,服务器就把相关的资源都推到客户端了吗?
喵星人哦
喵星人哦

引用来自“雷克”的评论

引用来自“yunfound”的评论

引用来自“车开源”的评论

引用来自“th小米粥”的评论

引用来自“我是小强”的评论

引用来自“th小米粥”的评论

不支持IE就是浮动。

唉,可怕的五笔,浮动

好吧。浮云。QQ五笔真坑爹。一样的编码竟然出现二个候选词。

同是扣扣五笔受害者

五笔是什么?

五笔难学, 全拼敲键盘累 , 双拼最爽

浮动,浮云,iefc
蝴蝶飘飘
蝴蝶飘飘
逆天了,这下子,http要变成有状态了
江振宇
江振宇
这个不跟websocket打架了吗?
返回顶部
顶部