nodejs-tw / ama

Ask me anything!
MIT License
31 stars 1 forks source link

重複使用 createReadStream #38

Open iamso1 opened 3 years ago

iamso1 commented 3 years ago

感謝使用 Node.js Taiwan AMA,以下附上簡單提問範例供參考,請把內容改成你自己遇到的問題

目的

我希望使用Nodejs 呼叫 API 上傳圖片到server 

使用的工具

希望使用 form 的方式上傳檔案 ( https://www.npmjs.com/package/form-data ) 我使用的是範例程式裡面的第三種方法

使用 fs.createReadStream的方法讀取圖片 最後post 這個 form 物件到 API去

form.append('my_file', fs.createReadStream('/foo/bar.jpg'));

操作流程

我會多次呼叫上傳 API 因為不希望每次都要重新讀取一次圖片 (fs.createReadStream) 所以在迴圈外面先讀取一次檔案, 像下面這樣:

const fileStream= fs.createReadStream('/foo/bar.jpg'));

(async()=>{
    for(let i=0;i<3;i++){
      const formData=new FormData();
      formData.append('file', fileStream);
      await axios.post('url', {data:formData} ) // 呼叫API 上傳剛剛的檔案
    }
})();

遇到的問題

API都會回應 http 504 timeout

嘗試過的解法

  1. 將createReadStream放在迴圈裡面, 即每次呼叫都重新讀取檔案 可正常執行 (但是拉出來回圈外面就會失敗) 查了原因應該是因為readStream 被讀取一次後 該stream 狀態就變成 readable: false

  2. 嘗試改存成 buffer (像form-data的第二種方法 如下:)

    form.append('my_buffer', new Buffer(10));

    配合使用fs.readfile的方法
    但是使用form-data 送到 API 時 就會失敗 好像只能用createReadStream能成功

shinder commented 3 years ago

用 buffer 是可以正常執行的

    const fs = require('fs');
    const axios = require('axios');
    const FormData = require('form-data');
    try {
        (async () => {
            const buffer = await fs.promises.readFile(__dirname + '/ttt.png');

            const formData = new FormData();
            formData.append('avatar', buffer, {filename: 'ttt.png'});
            formData.append('name', 'shinder');

            for (let i = 0; i < 3; i++) {
                await axios.post(
                    'http://localhost:3000/form1',
                     formData.getBuffer(),
                     {
                        headers: formData.getHeaders()
                    });
            }
        })()
    } catch(ex) {
        console.log('ex:', ex);
    }