fetch获取线上图片引发的思考
背景
起因是想下载一个套图但是貌似要 VIP 会员才能下载的样子,于是抱着侥幸的心理点开 F12 看了一眼,发现居然 src 就是图片的真实 uri,并且整个套图文件名数字是累加的, 嘴角疯狂上扬的同时决定写个脚本白嫖一下.
实现过程
该过程主要还是对 fetch 这个 api 的探究, 使用了能够运行在 node 中的node-fetch, 以下三种方法对图片音频进行下载测试均正常
stream
使用fetch返回的是一个Promise对象且resolve状态下的res.body是一个readablestream可读流,可以直接利用管道接到创建的可写流中.
1 | |
buffer()
利用node-fetch相较浏览器fetch特有的 buffer()方法
1 | |
arrayBuffer()
我们知道 node 中传输二进制数据需要通过buffer进行存储, 而 fetch 只提供了res.arrayBuffer()的方法, 所以在使用arrayBuffer()后还需要使用Buffer.from将arrayBuffer转化为buffer,这也是第二种方法简化的操作
1 | |
到这里已经对于获取远程文件的方法已经讲完了,下面是个人对其中不理解的部分的笔记
fetch 对比 ajax
之前一直觉得 fetch 与 $.ajax,axios 一样,对上面案例实践后发现还是自己菜了.
根据 MDN 上的描述:
Fetch API 提供了一个 JavaScript 接口,用于访问和操纵 HTTP 管道的一些具体部分,例如请求和响应。它还提供了一个全局 fetch() 方法,该方法提供了一种简单,合理的方式来跨网络异步获取资源。这种功能以前是使用 XMLHttpRequest 实现的。
也就是说 fetch 实际上是在Promise出现来解决callback hell前提下的一个新的异步获取资源的方案.
而 fetch与传统 ajax 的区别是
- 除非出现网络故障或请求被阻止的情况下,
fetch会将Promise状态置为reject,其余像响应状态码404,500,fetch都会将状态标记为resolve,但会将resolve的响应对象的ok属性置为false fetch不会接收跨域的cookie,即跨域响应头中的set-cookie将被忽略fetch默认不会跨域时发送cookie,(ajax 也是一样的), 默认fetch的credentials为same-origin
fetch 跨域
fetch 跨域需要后端配合CORS,后端需要对以下响应头字段进行设置,否则会报错
1 | |
之后,fetch设置fetch(url, {mode: 'cors'})即可进行跨域
若设置为{mode: 'no-cors'}, fetch不会进行报错,但会把Promise的resolve会返回ok: false, type: 'opaque'表明你没有权限访问

- Q: 提问! 后端没有提供
CORS,fetch需要怎么跨域? - A: 那就不要使用
fetch api, 建议JSONP.
arrayBuffer, Buffer, typedArray
对于arrayBuffer与typedArray都属于二进制数组,对于详细内容可以参考掘金的这篇文章:
掘金文章
这里做简述:
1 | |
下面这张图也能看出两者的关系:

Buffer 与 TypedArray
编写脚本时便有一个困扰,Buffer与arrayBuffer有啥关系? 这里记录一下.
Buffer是对Uint8Array的实现
Buffer对Uint8Array的相关 API 进行了实现,但 node 对Buffer类进行了优化,使之更适合在 node 下运行Buffer并不是完全兼容TypedArray实现
Buffer同样是一个Uint8Array类型数组实例。但它与 ES6 中的类型数组规范并不完全兼容,如:ArrayBuffer#slice()会创建一个分隔部分数据的拷贝,而Buffer#slice()会创建一个从 Buffer 中拷贝数据的视图,相对来说Buffer#slice()更高效。Buffer可以与类型数组共享内存区
可以从TypedArray的.buffer属性或new ArrayBuffer()创建一个 Buffer 对象。该对象会与类型数组共享内存区:
1 | |
回到开头那个困扰, 除了底层规范不完全兼容, 我们可以以Uint8Array来看待Buffer,并可以通过Buffer.buffer的方式获得ArrayBuffer.
延伸的实践
谈了那么多关于二进制数据的话题,现在对掘金文章中的一些小案例进行一下实践
获取远程图片并转换为 base64 格式
to be continue…