少女祈禱中...
Loading...
图片加载过慢?试试 从源站加载资源 X

ccloli

从 Fetch 到 Streams —— 以流的角度处理网络请求

Title image of Streams API by Mozilla Contributors is licensed under CC-BY-SA 2.5.

Title image of Streams API by Mozilla Contributors is licensed under CC-BY-SA 2.5.

此文章的略微润色版可前往 知乎掘金SegmentFault专栏 查看

在服务端开发中,流是一个很常见的概念。有了流我们就不再需要等待整个数据获取完毕后才处理数据,而是可以一段一段地拿到数据,在获得数据的同时直接解析数据。这样既可以高效利用 CPU 等资源,还减少了存放整个数据的内存占用。不过在过去,客户端 JavaScript 上都没有流的概念,而随着 Streams API 在各大浏览器上的逐步实现,我们终于可以使用原生的 API 以流的角度来看待数据了,例如从 fetch 请求上可以得到一个网络流。

既然标题是「从 Fetch 到 Streams」,那么首先让我们来看看既熟悉又陌生的 Fetch API。相比较于 XMLHttpRequestfetch() 的写法简单又直观,只要在发起请求时直接将整个配置项传入就可以了。fetch() 方法接受一个 Request 实例,或者是大家更常使用的方法——传入需要请求的 URL 以及一个可选的初始化配置项对象,然后就可以从 Promise 中取得返回的数据:

如果你不喜欢 Promise 的链式调用的话,还可以用 async/await

看起来相当的直观,在请求时直接将所有的参数传入 fetch() 方法即可,甚至相较于 XHR 还提供了更多的控制参数,例如是否携带 Cookie、是否需要手动跳转等;取出数据也只需要调用 Response 对象上的方法就能拿到格式化的数据(例如 res.json())。而直接使用 XMLHttpRequest 看起来就没那么方便了,初始化时既有方法的调用又有参数的赋值,看着还挺混乱的:

而随着 AbortControllerAbortSignal 在各大浏览器上完整实现,Fetch API 也能像 XHR 那样中断一个请求了,只是稍微绕了一点。通过创建一个 AbortController 实例,我们就得到了一个可以控制中断的控制器。这个实例的 signal 参数提供了一个 AbortSignal 实例,还提供了一个 abort() 方法用于发送中断信号。我们将 signal 传递进 fetch() 的初始化参数中,就可以在 fetch 请求之外控制请求的中断了:

只可惜提出这个解决方案并实装的时间还是有点晚,Fetch API 早在 就在 Firefox 上实现,并且最早于 在 Chrome 上实装。而该功能最早也是 Edge 浏览器在 2017 年 4 月实现,Safari 直到 2018 年末才被发现 AbortController 不能中断请求的 bug,最后在 2019 年 3 月的 Safari 12.1 中才正式解决。算下来从 Fetch API 在浏览器上实装开始,到主流现代浏览器全部支持,跨越了整整四年。

Image of AbortController & AbortSignal Support Table by caniuse.com is licensed under CC-BY 4.0.

Image of AbortController & AbortSignal Support Table by caniuse.com is licensed under CC-BY 4.0.

晚归晚,但是看起来现在的 Fetch API 已经无所不能了,不过在「真香」之前,我们来考虑一个很常见的场景:浏览器需要异步请求一个比较大的文件,由于可能比较耗时,希望在下载文件时展示文件的下载进度。XHR 提供了很多的事件,其中就包括了传输进度的 onprogress 事件,所以使用 XHR 可以很方便地实现这个功能:

但是 Fetch API 呢?你打开了 MDN,仔细地看了 fetch() 方法的所有参数,都没有找到类似 progress 这样的参数,毕竟 Fetch API 并没有什么回调事件。难道 Fetch API 就不能实现这么简单的功能吗?这里就要提到和它相关的 Streams API 了——不是 Web Socket,也不是 Media Stream,更不是只能在 Node.js 上使用的 Stream,不过和它很像。

READ MORE →

无显示器环境下用崩盘矿机搭建 NAS 小记

photo_2019-03-05_14-34-34

最早看到这条消息是月初摸鱼时逛贴吧看到某银子发的这个贴子(这里为某个自己把自己号删了的银子默哀一秒),某矿机老板跑路,剩下的矿渣开始在咸鱼上被 JS 倒卖。从贴子的信息可以大概得知这是一个类似于硬盘阵列柜的机器,每个机器上都有热插拔硬盘位,CPU 应该是 J1900。然后艰难地上咸鱼搜索了下 J1900(估计当天咸鱼已经被挤爆了,每次翻页都会跳转到服务器繁忙以及 504 Gateway Timeout,尤其是当天下午某在 GitHub 上发布消息的 JS 开卖,咸鱼 app 都会白屏,看来咸鱼是真的垃圾,把 web 砍掉情有可原……不对,现在真砍掉了,web 现在已经完全不能搜索了,会跳转 deny_pc,太垃圾了),刨去正常出 J1900 工控机和主板的卖家,还是能看到几个卖矿机的 JS,展示照片都是成堆的矿机,估计存量不小,价格普遍在 300 元左右。

为有时候可以是女的银子同学默哀一秒钟

为有时候可以是女的银子同学默哀一秒钟

于是摸鱼摸到底,某个 JS 在备注里留了个 GitHub 地址,关注了下,原来机器几天前就已经开始卖了,然后在看到贴子的前两天 JS 们统一战线,把价格定在了 300 左右。按照 GitHub 这位 JS 的描述,大概是说 300 块钱虽然也不是不合理,但是也觉得奇怪为什么定这个价,估计是这位 JS 觉得 300 定的有点高,虽然他接下来说因为发货的数量太多了,忙不过来,所以权当是辛苦费。

接下来 以「矿机」和「J1900」为关键词搜索,Google 上当时只有一个色魔张大妈的文章,文章中也提到最低价格入手是 200 多块钱,一开始大家都是试探着卖,不知道定价多少,结果 210 有人出了,慢慢涨价,最高涨到了 400。虽然文章中说矿机量大,估计有 20w 台,所以有可能有望跌破 200,不过按照前面那位 JS 的说法,估计是不太可能了。

smzdm 上的贴子就比较详细了,作者已经入手了两台机器,一台单网卡 A 一台双网卡 C,算是踩过了些坑。根据贴子描述,机器一共分为 ABC 三款(实际上还有个 D 款),各款还会分单双网口的版本。文章最后总结了下目前遇到的坑,诸如 C 款双卡是双卡单线需要改 BIOS,B 款双卡 BIOS 锁百兆,C 款双卡是 12 SATA,而 SATA III 是芯片扩展出来的,所以理论上来说 C 款双卡 12 SATA III + 1 SATA II 是最佳选择,但是求稳的话还是选择单卡比较好。具体的信息可以直接去原贴看,过去了一个月各种坑都出现了,文章内容应该充实了些。

这张图已经有新版本了,这是当时看到的图

这张图已经有新版本了,这是当时看到的图

不过毕竟是矿渣,以防有坑,还是持币观望一段时间比较好。果然接下来几天原贴的评论爆出了 B 款的 Intel 82583V 双卡全锁百兆,A 款也有概率拿到 B 款主板等问题,甚至还有出现 AB 款拿到 82583V 单卡同样锁百兆的问题。在千兆网卡都是瓶颈的今天,百兆的 NAS 还能用吗?最佳防坑百兆的方法是看机箱后是否有双 USB 3.0,单 USB 3.0 双卡基本是百兆,甚至单卡都有可能是百兆,实在不行只能额外掏钱买个 USB 3.0 的千兆网卡了(淘宝最低的一家价格应该是 40 左右,其他普遍要 70+,这成本就上去了),总之看来坑还是挺多的。所以后期基本上就考虑只选择 C 款或者 D 款(D 款的主板参数和 C 款基本一致,I211 网卡,双卡也是 12 SATA,内存随机 2GB/4GB 寨条),如果运气比较好价格差异不大的话可以上 12 SATA 的双卡版,毕竟 SATA III 是芯片扩展出来的,自然是将硬盘均分到每个芯片上会好些,以及双网卡万一能双路聚合呢(虽然看前文应该是一个千兆一个百兆,可能需要改 Intel I211 为 Intel I210,两个应该是同一个网卡,只是马甲不同)。只可惜上车时间已经比较晚了,几个咸鱼卖家表示没有 12 SATA 或者可能是开始惜售,或者有但是要价 400,所以最后经由 smzdm 原帖作者在交流群推荐的某咸鱼卖家上以 270 到付的价格拿到了 D 款单卡的版本。顺带后来还在淘宝上搜索了下 「NAS 机箱」,结果居然看到了来自华强北的 AB 同款机箱,淘宝价格单卖机箱就是 300+,所以实际上算一下 300 左右入手相当于是买机箱送主板和电源了,应该是不算亏的。

READ MORE →

[废稿] FFmpeg 推流指令小记

这是一篇废弃的文章。由于某些原因,本文未能最终成文,并且由于时间久远,已经没有成文的可能性,还请谨慎阅读。

若您需要了解最终解决方法,解决思路为:使用 Node.js 的 child_process 创建三个 FFmpeg 进程,第一个负责从文件列表循环读取文件并指定 -re 参数,然后使用统一的编码参数封装为 mpegts 格式,并输出到 stdout;第二个负责从一个预先录制好的黑屏视频 null.flv 并指定 -re 参数 copy 封装为 nut 格式(我也忘了为什么),并输出到 stdout;第三个负责从 stdin 中读取流,在指定 -err_detect aggressivecopy 封装为 flv 格式,推流到 RTMP 地址。将第一个进程 pipe 到第三个进程,当第一个进程转码完成一个文件后,立即将第二个进程 pipe 到第三个进程,防止推流中断,待第一个进程开始转码文件后再将第一个进程 pipe 到第三个进程。

本文实际发表于 2018 年 10 月 9 日。

最近在研究如何使用 FFmpeg 进行推流,所以在这里记录一下一些基本的命令行参数。

其实在研究 FFmpeg 的推流功能之前,自己也算稍微研究过一些 FFmpeg 的参数,比如下面这个 FFmpeg 录屏的辅助脚本:

总之 FFmpeg 就是一个非常强大的开源编解码解决方案,基于它可以实现绝大多数你所能想到的编解码功能。


下面的参数均是将视频源推到本地的直播源,源地址为 rtmp://localhost/live/ccloli

如果需要自己搭建本地直播平台进行测试,可以试试功能强大的 MistServer 或者短小精悍的 MonaServer

关于 FFmpeg 的具体指令介绍,此处不会完全详细解释,RTFM

如果你需要将一个文件进行推流,可以使用

其中 -re 参数描述如下,简单来说就是让输入的文件流按照指定的时间比率进行输入,从而保证输出流时间的稳定(如果不指定,很有可能会出现跳帧的情况);-i 即输入的文件;-c copy 代表对视频流和音频流都直接进行复制而不进行二次编码;最后是输出参数,-f flv 即 Flv 格式输出,最后输出到 rtmp 地址上。如果指定为一个文件名,那么它就是输出到一个文件。

-re (input)

Read input at native frame rate. Mainly used to simulate a grab device, or live input stream (e.g. when reading from a file). Should not be used with actual grab devices or live input streams (where it can cause packet loss). By default ffmpeg attempts to read the input(s) as fast as possible. This option will slow down the reading of the input(s) to the native frame rate of the input(s). It is useful for real-time output (e.g. live streaming).

如果你需要让这个源循环播放,可以用 -stream_loop 来循环输入流,指定数值为重复次数,-1 为无限循环

READ MORE →

在 OpenShift 上安装 Tesseract

最近教务系统的验证码又切换回了旧版的随机位置 + 斜体了,这学期弄的验证码识别也算是废了。这学期采用的新验证码虽然基本每个字符都有粘连,但是由于文本的位置基本是固定的,而且也没有过多的旋转,所以简单地取字模也是可以的(虽然识别率还是非常糟糕啦 _(:3)。现在换回了旧版后反而有些麻烦了,毕竟字符的旋转还是挺难处理的。由于自己用最好的编程语言写了个简单的爬虫,所以顺带试试看做验证码识别吧。

目前网上比较有名的 OCR 应该算是 Tesseract 了吧,Python 端的验证码识别软件 pytesser 就是基于 Tesseract 的。再加上前两年的时候 OpenShift 推出了 Build-It-Yourself 的玩意,就是一个应用 gear 里不仅可以安装 OpenShift 已经提供的 cartridge,用户还可以自己编写一个一键配置脚本,让 OpenShift 导入并安装。于是便考虑在 OpenShift 的一个应用上安装个 Tesseract,至于是不是违反 TOS 什么的再说啦先玩玩再说(x

OpenShift 的添加组件界面

READ MORE →

使用 CSS 跨域获取数据

最近有领导检查,上课不能愉快地玩手机和睡觉了。为了防止不省人事的情况,这家伙把几年前在二手东买的那本《DOM 启蒙》(其实我觉得应该和同系列的另一本书一样,译名为《DOM 启示录》,这样听起来比较厉害)带到了教室。嗯,虽然一直吐槽这本书的排版错误糟蹋了这本书,以至于给我这是盗版书的感觉,不过书的质量还是不错的。

花了一上午看完了整本书,算是把 DOM 整个又复习了一遍。回到寝室的路上突然想起了书中有一章提到可以获取样式表文件的属性,于是机(la)智(ji)的我想出了这么一个奇怪的问题:能不能用 CSS 实现跨域获取数据?

READ MORE →

乱谈 Blob 与 Object URL

* 此文纯粹只是乱谈而已,基本上是只知其一不知其二,还请各位菊苣指正 _(:3

由于某些需要,需要在 JS 里创建一个 Blob(Blob 对象就是包含有只读原始数据的类文件对象)并将数据存入,然后让用户保存它。将其交给用户的方式,对 IE 有一个奇奇怪怪的 navigator.msSaveBlob(),而对大多数现代浏览器来说,可以用 URL.createObjectURL() 来生成一个以 blob: 开头的地址来指向 Blob。目前的主流浏览器都是支持的(不过很可惜,Opera (Presto) 终于在它的最后一个大版本 12 版本实现了 blob,但没有实现 Blob URLs),然而不同浏览器对 Blob 的数据大小是有限制的。这里有份 FileSaver.js 的统计数据。

Browser Constructs as Filenames Max Blob Size
Firefox 20+ Blob Yes 800 MiB
Firefox < 20 data: URI No n/a
Chrome Blob Yes 500 MiB
Chrome for Android Blob Yes 500 MiB
IE 10+ Blob Yes 600 MiB
Opera 15+ Blob Yes 500 MiB
Opera < 15 data: URI No n/a
Safari 6.1+ Blob No ?
Safari < 6 data: URI No n/a
* FileSaver.js 开发者对不支持的浏览器做了一个叫 Blob.js 的兼容脚本,但其本质应该就是将 Blob 转为 data URL

READ MORE →

编程之美 2015 资格赛相关

嗯嗯,参加了之后才知道这种地方不是我等渣渣能去的地方 _(:3」∠)_ 虽然在 hihoCoder 上只要小数据能通过就可以进初赛,但是小数据排名的第一名三项全 AC,罚时只有两个多小时 _(:3」∠)_(虽然由于大数据没过而排名后延了,但现在的第一名还是两个多小时 orz),而且在讨论里他们说到什么“模拟退火”,完全听不懂 _(:3」∠)_ 果然我等只做了两题而且大数据全部 TLE 的渣渣只有当炮灰的命……

咳咳,炮灰归炮灰,还是来看看题目吧,嗯,解题什么的还是挺好玩的……

顺便,没有 JavaScript 差评

READ MORE →

使用 canvas 破解简单验证码

首先,其实这玩意并不算是完全的破解,因为它还需要人工录入的过程,而不是机器自动识别。如果是机器自动识别的话,那该是神经网络了吧——后文会给出一个别人写的例子……话说 CoffeeScript 是什么……

其次,这玩意只能破解非常简单的验证码,也就是那些出现位置固定、没有任何变形和干扰线,甚至颜色差别都不大的验证码,所以像下面这样的验证码还是洗洗睡吧,虽然还是可以识别出验证码的部分,但是识别的话……(canvas 阈值化 by 8q,咳咳,当然 example 也是我们参与的某个玩意的验证码,传说中的自黑

D2YUWF`3L(81`SZ{92TRV4U7O[W~8}V`YA3{]HTN1Z4A_K

再次,每个网站的验证码风格是不一样的,所以基本很难做到一个程序通杀所有验证码。如果真的有这么想过的话,真的可以洗洗睡了……中文验证码祝你好运……

最后,由于源码是手机码的,所以缩进不统一什么的 _(:3」∠)_……

READ MORE →

每天一首小苹果,感觉自己萌!萌!哒!

昨天中午无聊闲逛时,看到了 小苹果 转啊转 这个神奇的东西。觉得无聊于是决定学(shan)习(zhai)一下……

READ MORE →

萌否电台 HTML5 版本发布ww

请戳 MoeFM HTML5 Project | http://moefm.ccloli.com

READ MORE →