Lesson 08-Axios Upload and Download

File Upload Handling

Axios is a Promise-based HTTP client for browsers and Node.js, offering a simple yet powerful API for file uploads. Below are the basic steps and best practices for uploading files with Axios.

Preparing the File

In the frontend, you typically use a file input element (<input type="file">) to allow users to select files. Once a file is chosen, you can access it using JavaScript’s File interface.

Example Code:

<input type="file" id="fileInput">
document.getElementById('fileInput').addEventListener('change', function(e) {
  const file = e.target.files[0];
  uploadFile(file);
});

Creating a FormData Object

The FormData object is ideal for storing key-value pairs, especially for sending form data containing binary data like files.

function uploadFile(file) {
  const formData = new FormData();
  formData.append('file', file, file.name);
  // Add additional fields
  formData.append('description', 'A description of the file');

  axios.post('/upload', formData, {
    headers: {
      'Content-Type': 'multipart/form-data'
    }
  })
  .then(response => {
    console.log(response);
  })
  .catch(error => {
    console.error(error);
  });
}

Sending the Request

Use Axios’s post method to send the request. Since you’re uploading a file, set the Content-Type header to multipart/form-data, as this is the standard format for transmitting files and binary data.

Monitoring Upload Progress

For large file uploads, displaying a progress bar or updating the UI to reflect upload status is helpful. Axios allows tracking upload progress through request configuration.

axios.post('/upload', formData, {
  headers: {
    'Content-Type': 'multipart/form-data'
  },
  onUploadProgress: progressEvent => {
    const percentCompleted = Math.round((progressEvent.loaded / progressEvent.total) * 100);
    console.log(percentCompleted);
  }
})
.then(response => {
  console.log(response);
})
.catch(error => {
  console.error(error);
});

Backend Handling

On the server side, configure your server to handle multipart/form-data requests. The implementation depends on your backend framework or technology stack. For example, in Node.js, you can use middleware like multer or busboy to process file uploads.

Error Handling

Ensure robust error handling for issues like network failures, server errors, or file size limits.

Large File Chunked Upload

Uploading large files as a whole can lead to memory issues or network timeouts. Chunked uploading—splitting the file into smaller segments, uploading them separately, and merging them on the server—addresses these problems. Below are the steps and example code for chunked uploads with Axios.

Step 1: File Slicing

Split the file into smaller chunks on the client side using JavaScript’s Blob and File APIs.

function sliceFile(file, blockSize) {
  let slices = [];
  for (let i = 0; i < file.size; i += blockSize) {
    slices.push(file.slice(i, Math.min(file.size, i + blockSize)));
  }
  return slices;
}

Step 2: Uploading Chunks

Upload each chunk to the server using Axios. The server should provide an endpoint to receive chunks and track details like chunk index and total chunks.

const blockSize = 1024 * 1024; // 1MB
const fileSlices = sliceFile(file, blockSize);

fileSlices.forEach((slice, index) => {
  const formData = new FormData();
  formData.append('file', slice, `${index}-${file.name}`);
  formData.append('totalChunks', fileSlices.length.toString());

  axios.post('/upload-chunk', formData, {
    headers: {
      'Content-Type': 'multipart/form-data'
    }
  })
  .then(response => {
    console.log(`Chunk ${index} uploaded successfully`);
  })
  .catch(error => {
    console.error(`Failed to upload chunk ${index}: `, error);
  });
});

Step 3: Merging Chunks

On the server, implement logic to merge the chunks into a complete file, typically by reading chunks in order and writing them to a single file.

// Example server-side logic (Node.js)
const chunksDir = '/path/to/chunks';
const totalChunks = req.body.totalChunks;
const fileName = req.body.fileName;

// Merge chunks
let fullFile = fs.createWriteStream(`${chunksDir}/${fileName}`);
for (let i = 0; i < totalChunks; i++) {
  const chunkPath = path.join(chunksDir, `${i}-${fileName}`);
  fs.createReadStream(chunkPath).pipe(fullFile);
  fs.unlinkSync(chunkPath); // Delete merged chunk
}

Step 4: Error Handling and Retries

Handle network interruptions or server errors during chunk uploads by implementing a retry mechanism for failed chunks.

fileSlices.forEach((slice, index) => {
  const formData = new FormData();
  formData.append('file', slice, `${index}-${file.name}`);
  formData.append('totalChunks', fileSlices.length.toString());

  axios.post('/upload-chunk', formData, {
    headers: {
      'Content-Type': 'multipart/form-data'
    }
  })
  .then(response => {
    console.log(`Chunk ${index} uploaded successfully`);
  })
  .catch(error => {
    console.error(`Failed to upload chunk ${index}: `, error);
    // Retry logic
    setTimeout(() => {
      // Retry uploading chunk
      uploadChunk(slice, index);
    }, 5000); // Retry after 5 seconds
  });
});

File Download with Progress Tracking

Axios provides a convenient way to download files and track progress, which is particularly useful for large files to show users the download status.

Configuring an Axios Instance

Create an Axios instance to reuse configurations, such as base URL or default headers.

import axios from 'axios';

const instance = axios.create({
  baseURL: 'https://your-api-url.com',
  responseType: 'blob', // Set response type to blob for file handling
});

Downloading Files and Tracking Progress

Use Axios’s get method with responseType set to 'blob' to receive file data. Track download progress with the onDownloadProgress property.

instance.get('/download/path/to/file', {
  onDownloadProgress: progressEvent => {
    console.log(`Downloaded ${progressEvent.loaded} of ${progressEvent.total}`);
    // Update UI with download progress
    const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
    setProgressBar(percentCompleted);
  },
}).then(response => {
  // Handle downloaded file
  const url = window.URL.createObjectURL(new Blob([response.data]));
  const link = document.createElement('a');
  link.href = url;
  link.setAttribute('download', 'filename.extension'); // Specify filename
  document.body.appendChild(link);
  link.click();
});

Explanation:

  • onDownloadProgress: A callback invoked as data is downloaded, with progressEvent containing progress details.
  • responseType: ‘blob’: Ensures Axios returns a Blob instead of JSON.
  • createObjectURL and <a> tag: Trigger the browser’s download behavior after the file is received.

Error Handling

Handle potential errors like network issues or server failures.

instance.get('/download/path/to/file', {
  // ...
}).then(response => {
  // ...
}).catch(error => {
  console.error('Error downloading file:', error);
});
Share your love