Gửi các tệp lớn từ frontend đến backend

Mar 19 2023
Gần đây, trong một trong những cuộc phỏng vấn giao diện người dùng của tôi, Người phỏng vấn - Giả sử chúng tôi đang cung cấp cho người dùng tùy chọn tải tệp lên và lưu tệp đó. Sau đó, làm thế nào bạn sẽ gửi tệp đến chương trình phụ trợ? Tôi — Chúng tôi có thể gửi trực tiếp tệp đó trong phần nội dung của lệnh gọi API POST.

Gần đây, trong một trong những cuộc phỏng vấn frontend của tôi,

Người phỏng vấn — Giả sử chúng tôi đang cung cấp cho người dùng tùy chọn tải tệp lên và lưu tệp đó. Sau đó, làm thế nào bạn sẽ gửi tập tin đến phụ trợ?
Tôi — Chúng tôi có thể trực tiếp gửi nó trong phần nội dung của lệnh gọi API POST.

Người phỏng vấn — Nếu đó là một tệp lớn thì sao? giả sử, là 2GB.
Tôi - uh! Có lẽ chúng ta có thể nén tập tin và sau đó có thể chia nó thành nhiều phần và sau đó có thể gửi từng phần một.

Người phỏng vấn - Nhưng bạn sẽ làm điều đó như thế nào?
Tôi - tôi không thực sự chắc chắn. Tôi đã không gặp phải bất kỳ vấn đề như thế này cho đến nay.

Một cách để làm điều đó

Trong javascript, chúng tôi có một thứ gọi là FileReader . Những gì chúng ta có thể làm là tạo một đối tượng FileReader và sau đó chúng ta có thể đọc tệp đã tải lên dưới dạng bộ đệm mảng.

const fileReader = new FileReader();
fileReader.readAsArrayBuffer(file.files[0]); // file.files[0] shows the uploaded file

const fileReader = new FileReader();
fileReader.readAsArrayBuffer(file.files[0]); // file.files[0] shows the uploaded file
fileReader.onload = (event) => {}


fileReader.onload = async (event) => {
   const content = event.target.result;
   const CHUNK_SIZE = 1000;
 
   const totalChunks = event.target.result.byteLength / CHUNK_SIZE; // generate a file name
   const fileName = Math.random().toString(36).slice(-6) + file.files[0].name;

   for (let chunk = 0; chunk < totalChunks + 1; chunk++) {
       let CHUNK = content.slice(chunk CHUNK_SIZE, (chunk + 1) CHUNK_SIZE)
       await fetch('/upload?fileName=' + fileName, {
           'method' : 'POST',
           'headers' : {
               'content-type' : "application/octet-stream",
               'content-length' : CHUNK.length,
           },
           'body': CHUNK
       })
   }
}

Và bởi vì người dùng có thể muốn tải lên tệp có cùng tên tệp để đảm bảo chương trình phụ trợ hoạt động như mong đợi, nên chúng tôi cần một số nhận dạng duy nhất. Đối với điều đó, chúng tôi sử dụng một lớp lót tuyệt đẹp này:

Math.random().toString(36).slice(-6)

Bây giờ trên phần phụ trợ

Chúng ta có thể làm một cái gì đó như

if(req.url=== ‘/upload’ && req.method == ‘POST’) {
   const query = new URLSearchParams(req.url);
   const fileName = query.get(‘/upload?fileName’);
    
   req.on('data', chunk => {
     fs.appendFileSync(fileName, chunk); // append to a file on the disk
   })

   return res.end('successfully file uploaded!')
}