Вопрос или проблема
Я работаю над проектом с 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 правильно настроены на использование одного и того же формата данных при обмене информацией.