【Copy攻城獅日誌】Node.js之http下載圖片失敗

Created 2019-4-5 22:24:33 by huqi
Updated 2019-4-5 23:23:56 by huqi前端

clipboard.png
↑開局一張圖,故事全靠編↑node

從解答一個知否上的問題提及

有時候,本身就像本身在知否的簽名同樣--我覺得的就是我覺得的?一直以來,對前端技術的只知其一;不知其二一葉障目,致使我遇到問題老是片面,好比此次,就翻車了。技術水平就那樣,而後我竟然還想着幫人家解答,這不是誤人子弟嗎?昨天解答的這個問題,是關於node.js的http方法,根據Url獲取網絡圖片寫入到本地文件夾,這個需求我以前是玩過的,但用的是Copy&Paste的代碼,也沒有細細研究源碼,只知道用的是request的模塊,不過此次的哥們沒有依賴任何第三方模塊,只是用的內置的http模塊。他遇到的問題就是上圖所見,有一張圖片沒有下載成功沒法正常顯示。具體問題見@夜鷹 :用Node.js讀取遠程的圖片文件並寫入本地?git

clipboard.png

經過內置http模塊下載圖片源碼

  • 引入內置http模塊發起請求獲取文件
  • 引入內置fs模塊寫入文件
const http = require('http')
const fs = require('fs')

const urlArr = [
'http://img.zcool.cn/community/01e505554437be0000019ae95582a2.jpg@900w_1l_2o_100sh.jpg',
'http://static.pig66.com/uploadfile/2017/1102/20171102095531217.png',
]

urlArr.forEach(url => {
    getImg(url)
})

function getImg(url, name) {
    http.get(url, {encoding: null}, res => {
        let img = []
        let size = 0
        // 將圖片地址以【.】符號分割,取最後一項,即爲格式後綴
        const _arr = url.split('.')
        const format = _arr[_arr.length - 1]
        // 若是沒有傳入圖片名字,則使用隨機數
        const _name = name ? name : 'image-' + Math.floor(Number(new Date()) * Number(Math.random()))
        res.on('data', chunk => {
            img.push(chunk)
            size += chunk.length
        })
        res.on('end', () => {
            // 合併 Buffer
            const buffer = Buffer.concat(img, size)
            fs.writeFileSync(`img/${_name}.${format}`, buffer, (err) => {
                if (err) {
                    return console.error(err);
                }
                console.log("數據寫入成功!");
            })
        })
    })
}

對來講,起初我覺得是文件太大的緣由,由於經過輸出查看到Buffer數據中斷並直接結束了。後來我試了下1M左右的圖片,徹底可以成功下載,然而,打臉啪啪啪。接下來,我草率地下告終論,並丟給博主一段使用第三方模塊request的一樣功能的實現(見歷史版本:共被編輯 4 次)。真相糾結是怎樣的?另外一位答主@啊哦 已經給出了至關明確的答案!github

clipboard.png

「罪魁禍首」--301重定向

301重定向()頁面永久性移走)是一種很是重要的「自動轉向」技術。網址重定向最爲可行的一種辦法。當用戶或搜索引擎向網站服務器發出瀏覽請求時,服務器返回的HTTP數據流中頭信息(header)中的狀態碼的一種,表示本網頁永久性轉移到另外一個地址。

打開圖片連接:http://www.pig66.com/uploadfi...,經過查看Network,咱們清晰地看到源圖片有作301重定向。經過在源代碼中添加日誌輸出,咱們也能清楚地看到301的狀態碼。
clipboard.pngsegmentfault

clipboard.png

既然問題的根源已經找到,那就對症寫bug,若是是301的話獲取請求返回的真實地址再次發起請求。服務器

const { statusCode } = res
        if ( statusCode === 301 ) {
            const url = res.headers['location']
            return getImg(url)
        }

修改後的代碼:網絡

const http = require('http')
const fs = require('fs')

const urlArr = [
'http://img.zcool.cn/community/01e505554437be0000019ae95582a2.jpg@900w_1l_2o_100sh.jpg',
'http://static.pig66.com/uploadfile/2017/1102/20171102095531217.png',
]

urlArr.forEach(url => {
    getImg(url)
})

function getImg(url, name) {
    http.get(url, {encoding: null}, res => {
        const { statusCode } = res
        console.log(statusCode)
        if ( statusCode === 301 ) {
            const url = res.headers['location']
            return getImg(url)
        }
        let img = []
        let size = 0
        // 將圖片地址以【.】符號分割,取最後一項,即爲格式後綴
        const _arr = url.split('.')
        const format = _arr[_arr.length - 1]
        // 若是沒有傳入圖片名字,則使用隨機數
        const _name = name ? name : 'image-' + Math.floor(Number(new Date()) * Number(Math.random()))
        res.on('data', chunk => {
            img.push(chunk)
            size += chunk.length
        })
        res.on('end', () => {
            // 合併 Buffer
            const buffer = Buffer.concat(img, size)
            fs.writeFileSync(`img/${_name}.${format}`, buffer, (err) => {
                if (err) {
                    return console.error(err);
                }
                console.log("數據寫入成功!");
            })
        })
    })
}

成功拿到圖片,並能直觀的感覺到301重定向以後又發起了一次請求,dom

clipboard.png

clipboard.png

後記

這兩天朋友託我寫兩個簡單的頁面,我發現本身啥也不會!想一想我,竟然還這麼熱心地去幫人解答,真的是誤人子弟貽害不淺。謹以這次經歷深入檢討自我,對被我坑過的各位表示深切的歉意。同時,也但願各位大佬不惜多多賜教!最後,祝@jsliang 生日快樂!寫在生日,一年前端拼搏記post

相關文章
相關標籤/搜索