低成本打造一个带宽无限的网站(四)

分块处理

上一篇曾提到,我们可对资源加密存储,然后在 SW 中进行解密。

理论上这当然可行,但事实上会出现一些问题:我们必须等整个资源下载完成后,才能开始解密操作。这对于用户体验,会产生很大的影响。

假如有个 1MB 的图片,通过 100 KB/s 的速度加载,那么要 10 秒后才能解密再展示;然而正常情况下,图片是边加载边显示的,并不会让用户等很久,然后一次性展示所有的。

为了解决这个问题,一个期待已久的新标准终于到来,那就是 Stream API。

有了流的支持,数据就可以渐进处理,而不必等待完整的。例如,我们使用 fetch 分块读取内容:

// fetch 分块读取演示
async function load(url) {
    let res = await fetch(url);
    console.log('response:', res);

    let reader = res.body.getReader();
    for (;;) {
        let r = await reader.read();
        if (r.done) {
            break;
        }
        console.log('chunk:', r.value);
    }
    console.log('end');
}

load('https://raw.githubusercontent.com/EtherDream/_/master/pic.jpg');

演示:codepen.io/anon/pen/zPKrGX

同时,SW 也支持数据分块输出给下游:

// SW 分块输出
let stream = new ReadableStream({
    start(controller) {
        ...
        input.ondata = function(chunk) {
            controller.enqueue(chunk);
        };
        input.onend = function() {
            controller.close();
        };
        ...
    }
});

let res = new Response(stream, ...);
...

两者结合,我们就可以实现边下载、边解密、边输出的效果。于是对于加密的图片、视频等资源,也能循序渐进地展示了!

下载加速

除了解密、解压缩等场合,数据流还可用于传输优化。例如,用户下载大文件的场合。

由于免费空间单个节点的带宽是有限的,因此下载速度不会太快。这时就可以通过 SW 做加速了 —— 我们同时从多个节点获取相应的文件片段,然后依次输出到响应流里:

在用户看来,这只是浏览器默认的单线程下载,但事实上内部已通过 SW 加速,和传统的多线程下载软件并无本质区别!

当然,就算免费空间不支持 Range 请求也没关系,我们可事先把大文件分成多个小文件上传,然后分别加载即可。

动态加速

上一篇提到,通过 SW 可对故障节点「实时无缝」的切换。现在有了数据流,我们可将其发挥到极致,甚至能在传输的过程中进行调整。

例如,SW 默认选择节点 1 加载资源,但发现速度没有预期的那么快,于是可增加节点 2 参与加速:

这样,我们就能根据用户的实际网络情况,在端上动态调整,从而实现更智能的负载均衡!

插入脚本

有时候,我们希望给站点下所有页面的头部插入一个 JS 脚本。

这个功能,如果没有数据流支持的话,那么 SW 必须得下载整个 HTML 才能修改;而现在,我们只需改造最先返回的几个 chunk 即可!

不过需要注意的是,chunk 是二进制层面截断的,因此可能把多字节字符截成两半,导致出现乱码。

为此,我们需要用「流模式」解码字符串。例如:

// stream decode example
let dec = new TextDecoder();
let chunk1 = new Uint8Array([228, 189, 160, 229, 165]);
let chunk2 = new Uint8Array([189]);

dec.decode(chunk1, {stream: true});     // "你"
dec.decode(chunk2, {stream: true});     // "好"

如果 chunk 末尾的字符不完整,那么不足的部分则被暂存在内部,下次解码时会自动加在开头。

这样,我们就能用字符串方法,更方便地操作二进制数据了:

let dec = new TextDecoder();
let enc = new TextEncoder();

input.ondata = function(chunk) {
    // 二进制 -> 字符串
    let str = dec.decode(chunk, {stream: true});

    // 插入脚本元素
    str = str.replace(/<head/i, '<script ...><head');

    // 字符串 -> 二进制
    chunk = enc.encode(str);
    ...
};

当然,这里的逻辑还有点瑕疵 —— 假如 <head 这个字符串正好跨越两个 chunk,那就无法匹配到了。

由于 JS 不支持流模式的正则匹配,因此可以用个土办法:如果 str 匹配不到,则截掉末尾 5 个字符,然后将尾巴暂存起来,拼到下一次的头部。。。这样虽然没有流那么严格,但实现简单,并且也很高效。

此外,由于我们只需替换一次,因此之后可跳过这步,无需解码、匹配、编码了。

小结

在数据流的配合下,SW 可实现非常丰富的玩法。不过目前只有 Chrome 浏览器支持 Stream API,因此兼容性也是个较大的问题。相信随着新标准的普及,今后使用前端加速的网站,一定会越来越多。

然而对于我们的「免费空间」来说,除了兼容性问题之外,还有 SW 的各种使用限制也是一个挑战。因此如何绕过 SW 的使用限制,也是需要我们思考的。

下一篇

时间: 2024-11-03 16:29:09

低成本打造一个带宽无限的网站(四)的相关文章

低成本打造一个带宽无限的网站(五)

突破限制 由于 SW 非常强大,因此使用条件也是非常严格的,以免被恶意使用. 例如 SW 必须在 HTTPS 站点上使用.这本是件好事,彻底杜绝了中间人的隐患,但现在却成了一道门槛 -- 毕竟支持 HTTPS 并且域名可控的免费空间,那是极少的. 同时,这还引发了另一个问题:由于 HTTPS 站点是禁止读取 HTTP 数据的,因此我们的节点也必须是 HTTPS 站点! 此外 SW 也得遵守同源策略.如果要读取第三方站点的数据,目标响应头里还得有 Access-Control-Allow-Orig

低成本打造一个带宽无限的网站(二)

网站攻击 有次在讨论网站防护时,提到一个信息发布的站点 -- 它的结构很简单,只有几个页面而已,正常情况下打开是非常快的.然而一到关键时刻,流量如同洪水般涌来.网站无法访问,那些付费发布的信息就错过最佳展现时间了. 对于网站攻击,现成的解决方案有很多,例如用上 WAF.CDN 等服务,多少能分担一些.不过,通用的防御方案,自然就有通用的攻击方案. 例如通过 DNS 实现的负载均衡,攻击者使用现成的工具,就能轻易遍历出对应的 IP.更糟的是,有时域名会缓存很久,使得攻击都快结束了解析还没生效. 对

低成本打造一个带宽无限的网站

前言 前些年断断续续写的,最近突然想起来,于是翻出来又补充了一些,目前整理了几篇: 第 1 篇 -- 免费空间的遐想 第 2 篇 -- 通过缓存防御网站 第 3 篇 -- 前端代理服务 第 4 篇 -- 数据流优化 第 5 篇 -- 免费空间的挖掘 配图是 SVG 格式的,由于无法上传,目前放在 GitHub Pages 上.如果速度很慢或者被墙,可以开代理试试. 免费空间 自从学习网页制作那天起,就开始期待有朝一日能有个自己的网站. 尽管当时有不少免费空间,对于简单的个人网站也够用了,然而像我

程序猿如何快速打造一个有设计感的网站

  像我这样的程序员来说经常被"设计"这个词吓到,因为我是一名程序员而不是设计师,我拥有的是计算机学位证,另外我对 Comic Sans 字体并不介意.(注:Comic Sans 字体是 Win95 附带的一种漫画字体,设计行业极为排斥,设计师或那些拥有美学情结的人不屑与之为伍) 虽然只是一名程序员,但我还是想让自己的网站看起来更加吸引人,一方面出于虚荣,因为这样可以显得我更加"专业",而另一方面是出于现实,因为研究机构调查发现用户会更加信任那些网站"看起

码农如何快速打造一个有设计感的网站

注:拥有属于自己的网站是很多人的梦想,但大多数人只能借助像 WordPress 这样的 CMS 实现,甚至很多公司网站也是这样.但这些网站大多数看起来都比较缺乏设计感,通俗来讲就是有点"土".那么对于像程序员以及其他对设计比较小白们来说,如何能让你的网站看起来更加前卫,有范,有设计感呢?极客公园编译了 24WAYS 的文章 How to Make Your Site Look Half-Decent in Half an Hour 为您提供解决方法. 像我这样的程序员来说经常被&quo

如何利用SEO打造一个成功的购物网站

电子商务崛起,无论是国内还是国外的互联网,都涌现出大量的http://www.aliyun.com/zixun/aggregation/7976.html">在线购物网站.竞争太过于激烈,如何让用户优先找到自己的网站.这是很多的购物网站的管理员都在思考的问题. 电子商务是与搜索引擎高度结合的一个行业,至少在目前来说是这个样子.大部分想在网上购物的用户,都会先在搜索引擎上搜索物品的相关信息,最后找到产品或服务的供应商. 根据思亿欧的调查,购物网站在互联网(指国内互联网)上面临的竞争更严峻.无

如何打造一个成功的购物网站

电子商务崛起,无论是国内还是国外的互联网,都涌现出大量的http://www.aliyun.com/zixun/aggregation/7976.html">在线购物网站.竞争太过于激烈,如何让用户优先找到自己的网站.这是很多的购物网站的管理员都在思考的问题. 电子商务是与搜索引擎高度结合的一个行业,至少在目前来说是这个样子.大部分想在网上购物的用户,都会先在搜索引擎上搜索物品的相关信息,最后找到产品或服务的供应商. 购物网站在互联网上面临的竞争更严峻.无论你的购物网站是从事销售数码.服装

教你快速打造一个有设计感的网站

对于好多程序员来说,经常被"设计"这个词吓到,因为Ta是一名程序员而不是设计师,拥有的是计算机学位证,另外对 Comic Sans 字体并不介意.(注:Comic Sans 字体是 Win95 附带的一种漫画字体,设计行业极为排斥,设计师或那些拥有美学情结的人不屑与之为伍.更多查看这篇为什么不要使用 Comic sans 字体) 虽然只是一名程序员,但还是想让自己的网站看起来更加吸引人,一方面出于虚荣,因为这样可以显得更加"专业",而另一方面是出于现实,因为研究机构

如何两个月打造一个盈利的B2B网站

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 接触网络已经7年了,行业站也做了好几个了,尝试了几个行业都没有盈利,最后结合自身的优点,因为自己在铸造行业的国家级期刊媒体呆了7年,做了七年的广告主管,毕竟自己在这个行业有一定的客户群,做铸造网应该没有问题,想好了后就开始动手了. 首先,想好域名.域名很重要,一个好的域名能够带来很大的回头客,而且名字好记,客户能一下子记住你.但是马云刚开始做