在爬取壁纸的时候,需要将其下载到本地,本着不重复造轮子的信念,想着是否有成熟的三方库可以直接调用,逛了一圈后,发现最近更新是在三年前!o(╯□╰)o

无奈,只能自己“造个轮子”了……

一般的方式是先调用http接口发起请求爬取图片,然后再调用文件接口保存图片。如下:

typescriptCopy code
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
http.get(url, (req, res) => { let imgData = ''; req.on('data', (chunk) => { imgData += chunk; }) req.setEncoding('binary'); req.on('end', () => { writeFile(savePath, imgData, 'binary', (err) => { ... }) }) })
http.get(url, (req, res) => { let imgData = ''; req.on('data', (chunk) => { imgData += chunk; }) req.setEncoding('binary'); req.on('end', () => { writeFile(savePath, imgData, 'binary', (err) => { ... }) }) })

或者调用creatWriteStream

typescriptCopy code
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
http.get(url, (res) => { const ws = createWriteStream('/path/to/save/wallpaper.jpg') res.pipe(ws) ws.on('finish', () => { ... }); ws.on('error', () => { ... }); })
http.get(url, (res) => { const ws = createWriteStream('/path/to/save/wallpaper.jpg') res.pipe(ws) ws.on('finish', () => { ... }); ws.on('error', () => { ... }); })

第2种方式虽然已经较前一种更为优雅、高效,但还是有些繁琐,毕竟,依然包含了3个回调函数,对于流程控制或者错误处理,无疑都增加了不少负担。因此,需要一种更科学、合理、有效的方式。

查看Nest.js的API,发现HttpService中有一个axiosRef方法,就是它了!最终版代码如下:

typescriptCopy code
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
async download(url: string, path: string) { const writer = createWriteStream(path); const response = await this.httpService.axiosRef({ url, method: 'GET', responseType: 'stream' }); response.data.pipe(writer); return new Promise((resolve, reject) => { writer.on('finish', resolve); writer.on('error', reject); }); }
async download(url: string, path: string) { const writer = createWriteStream(path); const response = await this.httpService.axiosRef({ url, method: 'GET', responseType: 'stream' }); response.data.pipe(writer); return new Promise((resolve, reject) => { writer.on('finish', resolve); writer.on('error', reject); }); }

此方式充分利用了createWriteStreamHttpServicePromise等新特性,尤其是其中的管道操作,简直是效率、性能利器;而最后的回调处理也完美地转换成了Promiseresolvereject方式,充分发挥了ES6的异步编程优势。

如此,再去实现图片的下载就很容易了:

typescriptCopy code
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
const response = await this.httpService.axiosRef({ url: imageUrl, method: 'GET', responseType: 'stream' }); res.set({ 'Content-Type': imageType || 'image/jpeg', 'Content-Disposition': `attachment; filename=${fileName}` }); response.data.pipe(res);
const response = await this.httpService.axiosRef({ url: imageUrl, method: 'GET', responseType: 'stream' }); res.set({ 'Content-Type': imageType || 'image/jpeg', 'Content-Disposition': `attachment; filename=${fileName}` }); response.data.pipe(res);

完美![]~( ̄▽ ̄)~*