Home > Back-end >  how to send and receive file by flask and axios
how to send and receive file by flask and axios

Time:02-21

In the node js, I send a post request, and hope to receive a file from the python flask server. What it sends is not relavent, and I just would like to receive the a jpeg file from the flask server:

const fs = require('fs');

const axios = require('axios');

const BASE_URL = "http://localhost:5000";

function send_test(test_name,...args) {
    const apiurl = `${BASE_URL}/send`;
    
    
    const form = new URLSearchParams();
    form.append('filename', test_name);
    const config = {
        headers: {
            'content-type': 'multipart/form-data'
        }
    };
    axios.request({
        url: apiurl,
        method: 'POST',
        headers:config,
        data: form,
    
    })
        .then(function (response) {
        
            
            console.log(response.data);
            fs.writeFileSync('result.jpeg', 
            response.data);
        
  })
  .catch(function (error) {
        console.log(error);
        
  });

}
result = send_test('test_name');

The flask server returns a jpeg, and it does not matter what it receives from the node js, it does not check the form and just sends a jpeg file:

from flask import Flask, request,send_file
import os

app = Flask(__name__)


@app.route('/send', methods=['POST'])
def send():
    print('send')

    extracted_name = 'test.jpeg'
   
        
    return send_file(extracted_name, mimetype="image/jpeg")

However, when I save file to 'result.jpeg', the file cannot be opened. I think the encoding of the file is important here. How to save the file by fs.writeFileSync()? The first a few bytes of response.data is like :

����JFIFHH��xExifII*1>i�FPicasa�0220�� ���C

CodePudding user response:

I can't see from your question why you want to use a post request. In my opinion, a get request is sufficient to download a file.
In the example below, a file is downloaded and saved with a get request. A variable rule is used to select the file name. The file is obtained and saved as a stream.

function downloadFile(src, dst) {
  axios
    .get(src, { responseType: 'stream' })
    .then(async resp => {
      resp.data.pipe(fs.createWriteStream(dst));
    });
}

downloadFile(
  'http://localhost:5000/download/test.jpeg',
  'result.jpeg'
);
@app.route('/download/<path:filename>')
def download(filename):
    return send_from_directory(app.static_folder, filename)

If you still want to send form data to the server, you can slightly modify the example to achieve your goal.

function downloadFile(src, dst) {
  const url = 'http://localhost:5000/send';
  const formData = new FormData();
  formData.append('filename', src);
  axios
    .post(url, formData, { headers: formData.getHeaders(), responseType: 'stream' })
    .then(async resp => {
      resp.data.pipe(fs.createWriteStream(dst));
    });
}

downloadFile(
  'test.jpeg',
  'result.jpeg'
);

If you want to upload a file with axios, I recommend the following procedure.

const url = 'http://localhost:5000/upload';
const filePath = path.resolve('result.jpeg');
fs.readFile(filePath, async (error, data) => {
  if (error) {
    console.log(error);
    return;
  }
  const formData = new FormData();
  formData.append('file', data, { filepath: filePath, contentType: 'image/jpg' });
  axios
    .post(url, formData, { headers: formData.getHeaders() })
    .then(resp => {
      console.log('File uploaded successfully.');
    });
});
@app.route('/upload', methods=['POST'])
def upload():
    file = request.files.get('file');
    # Process the file here.
    return '', 200

There are several ways to send a file and JSON data in one.

Send JSON data in HTTP header:
from flask import send_file
import json

@app.route('/send')
def send_json_binary():
    filename = 'test.jpeg'
    resp = send_file(filename, mimetype='image/jpeg')
    resp.headers['X-Metadata'] = json.dumps({
        'filemeta': 'Your metadata here.'
    })
    return resp
function downloadFile(src, dst) {
  axios
    .get(src, { responseType: 'stream' })
    .then(async resp => {
      const meta = JSON.parse(resp.headers['x-metadata'])
      const filemeta = meta.filemeta;
      resp.data.pipe(fs.createWriteStream(dst));
    });
}

downloadFile(
  'http://localhost:5000/send',
  'result.jpeg'
);
Sending Base64 encoded data within JSON:
from flask import jsonify
from base64 import b64encode

@app.route('/sample')
def send_json_binary():
    filename = 'test.jpeg'
    with open(filename, 'rb') as fh:
        return jsonify(
            filemeta = 'Your metadata here.',
            filedata = b64encode(fh.read()).decode()
        )
function downloadFile(src, dst) {
  axios
    .get(src, { responseType: 'json' })
    .then(async resp => {
      const meta = resp.data.filemeta;
      const buffer = Buffer.from(resp.data.filedata, 'base64');
      const stream = Readable.from(buffer);
      stream.pipe(fs.createWriteStream(dst))
    });
}

downloadFile(
  'http://localhost:5000/send',
  'result.jpeg'
);

It depends on your requirements which way you go.

  • Related