Ошибка Axios при выполнении POST-запроса .txt файла

Вопрос или проблема

Я работаю над проектом с Flask и React, и в данный момент я разрабатываю конечную точку API, которая позволяет получать .txt файл от фронтенда, после чего запускается скрипт, анализирующий данные из этого .txt и сохраняющий графики, связанные с анализом.

Вот конечная точка API на бэкенде:

@analysis_ns.route('/upload', methods=["POST", "GET"])
class ChatAnalysisUploadResource(Resource):
    def get(self):
        return {"message": "Эта конечная точка предназначена только для загрузки файлов через POST."}, 405

    #@jwt_required()
    def post(self):
        """Загрузите файл чата, обработайте его и верните URLs изображений"""
        try:
            if 'file' not in request.files:
                abort(400, description="Не указана часть файла")

            file = request.files['file']

            if file.filename == '':
                abort(400, description="Не выбран файл")

            if file and allowed_file(file.filename):
                filename = secure_filename(file.filename)
                file_path = os.path.join(UPLOAD_FOLDER, filename)
                file.save(file_path)

                # Обработайте файл и создайте изображения
                process_chat_file(file_path)

                image_paths = ['static/mensajes_enviados.png', 'static/emojis.png']
                missing_images = [path for path in image_paths if not os.path.exists(path)]

                if missing_images:
                    abort(500, description=f"Изображение не найдено: {missing_images}")

                image_urls = {
                    'urls': [
                        url_for('static', filename="mensajes_enviados.png", _external=True),
                        url_for('static', filename="emojis.png", _external=True)
                    ]
                }

                # Сохраните результаты в базе данных
                result_summary = ";".join(image_urls['urls'])
                new_analysis = ChatAnalysisResults(
                    chat_name=filename,
                    result_summary=result_summary
                )
                new_analysis.save()

                return jsonify(image_urls), 200

            abort(400, description="Тип файла не разрешен")

        # Поймайте ошибку и верните сериализуемое сообщение
        except Exception as e:
            return jsonify({"error": str(e)}), 500

А вот React-компонент, который обрабатывает загрузку документа (я не очень хорош в React):

import { useState } from 'react'
import PropTypes from 'prop-types'
import axios from 'axios'
import '../App.css'

function UploadForm({ setImages }) {
    const [file, setFile] = useState(null);
    const [response, setResponse] = useState('');
    const [loading, setLoading] = useState(false);

    const handleFileChange = (event) => {
        setFile(event.target.files[0]);
    };

    const handleUpload = async () => {
        if (!file) {
            alert("Пожалуйста, выберите файл чата для загрузки.");
            return;
        }

        const formData = new FormData()
        formData.append('file', file) // Изменено с 'chat_file' на 'file'

        setLoading(true) // Начинает анимацию загрузки
        setImages([])   // Очищает предыдущие результаты
        setResponse('') // Необязательно: очищает сообщение ответа

        console.log('Загрузка началась');

        try {
            const response = await axios.post('http://127.0.0.1:8080/analysis/upload', formData, {
                headers: {
                    'Content-Type': 'multipart/form-data'
                }
            });

            console.log('Данные ответа:', response.data);

            setImages(response.data.urls);
            setResponse('Файл чата успешно проанализирован');
        } catch (error) {
            console.error('Ошибка при загрузке файла:', error);
            setResponse('Ошибка при загрузке файла: ' + (error.response ? error.response.data.error : error.message));
        } finally {
            setLoading(false); // Останавливает анимацию загрузки независимо от результата
            console.log('Загрузка завершена');
        }
    }

    return (
        <div className="upload-form">
            <input type="file" onChange={handleFileChange} accept=".txt" />
            <button onClick={handleUpload}>
                {loading ? 'Анализирую' : 'Проанализировать чат'}
            </button>
            {response && <p>{response}</p>}
            {loading && (
            <div className="loading">
                <div className="spinner"></div>
            </div>
            )}
        </div>
    )
}

UploadForm.propTypes = {
    setImages: PropTypes.func.isRequired, 
}

export default UploadForm

И вот ошибка, которую я получаю в консоли:

вставьте описание изображения здесь

Кроме того, ошибка, которую я вижу в терминале VSCode, следующая:

  File "/opt/anaconda3/lib/python3.11/json/encoder.py", line 180, in default
    raise TypeError(f'Объект типа {o.__class__.__name__} '
TypeError: Объект типа Response не может быть сериализован в JSON

Все конечные точки API до сих пор работают правильно, за исключением этой, я уже запутался с этой проблемой на протяжении недели и мне нужна помощь. Если вам нужна дополнительная информация или вы хотите увидеть другие части/скрипты проекта, не стесняйтесь спрашивать 🙂

Я вижу, что в вашем коде есть ошибка политики CORS. Она возникает из-за того, что вы работаете с двумя разными URL-адресами, один для бэкенда и один для фронтенда, и для ее решения вам нужно внести изменения в ваш код Flask. Установите пакет flask_cors и затем импортируйте модули из него;

from flask_cors import cross_origin  #для конкретного маршрута
from flask_cors import CORS  #для всего приложения

после импорта

analysis_ns = Flask(__name__)  #вы, возможно, сделали это в начале вашего кода
CORS(analysis_ns)  #для включения CORS в все приложение, определите его в начале вашего кода

#остальная часть вашего кода

@analysis_ns.route('/upload', methods=["POST", "GET"])
@cross_origin  #для включения CORS для конкретного маршрута

#остальная часть вашего кода

Это может помочь разрешить ошибку. У меня была проблема с политикой CORS во время стажировки, где я работал с той же технологией, а именно, Flask и React.

Ответ или решение

Для решения проблемы с ошибкой Axios при выполнении POST-запроса на загрузку .txt файла в вашем проекте Flask и React, рассмотрим несколько возможных причин и решений проблемы.

1. Проблема с CORS (Cross-Origin Resource Sharing)

Наиболее вероятной причиной проблемы является политика CORS, так как вы выполняете запросы между разными доменами или портами (например, React может находиться на http://localhost:3000, а Flask на http://127.0.0.1:8080). Для решения этой проблемы вам необходимо установить библиотеку flask-cors.

Установка flask-cors:

pip install flask-cors

Импорт и настройка CORS в вашем приложении:

from flask_cors import CORS

# Предполагаем, что analysis_ns – это ваш объект Flask приложения
app = Flask(__name__)
CORS(app)  # Включает CORS для всего приложения

@analysis_ns.route('/upload', methods=["POST", "GET"])
@cross_origin()  # Включает CORS только для этого маршрута
class ChatAnalysisUploadResource(Resource):
    ...

2. Обработка ошибок в API

Ошибка TypeError: Object of type Response is not JSON serializable указывает на то, что вы пытаетесь вернуть объект типа Response из вашего API в качестве JSON. Для исправления этого:

  • Убедитесь, что все ответные сообщения формируются в формате JSON и не содержат ссылки на объекты Flask. В вашем коде это может потребовать изменения способа обработки ошибок:
except Exception as e:
    return jsonify({"error": str(e)}), 500  # Убедитесь, что возвращаете словарь, который можно сериализовать

3. Проверка правильности отправки данных из React

В вашем React компоненте код выглядит достаточно корректно, но убедитесь, что загружаемый файл действительно соответствует формату .txt:

const handleUpload = async () => {
    if (!file) {
        alert("Пожалуйста, выберите файл для загрузки.");
        return;
    }

    const formData = new FormData();
    formData.append('file', file); // Используем правильное имя поля 'file'

    setLoading(true);
    setImages([]);
    setResponse('');

    try {
        const response = await axios.post('http://127.0.0.1:8080/analysis/upload', formData, {
            headers: {
                'Content-Type': 'multipart/form-data'
            }
        });

        setImages(response.data.urls);
        setResponse('Файл чата успешно проанализирован');
    } catch (error) {
        console.error('Ошибка при загрузке файла:', error);
        setResponse('Ошибка при загрузке файла: ' + (error.response ? error.response.data.error : error.message));
    } finally {
        setLoading(false);
    }
};

4. Отладка и вывод ошибок

Используйте консоль и возможные выводы для отладки. Например, вы можете вывести содержимое переменной error в вашем catch блоке для лучшего понимания, какая именно ошибка происходит.

Заключение

После внесения вышеперечисленных изменений, ошибка при загрузке .txt файла должна быть исправлена. Если вы продолжаете сталкиваться с проблемами, проверьте настройки вашего серверного окружения и наличие необходимых библиотек. Убедитесь также, что ваши API и компонент React правильно настроены на использование одного и того же формата данных при обмене информацией.

Оцените материал
Добавить комментарий

Капча загружается...