You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

POST上传TXT文件时Axios报错及Flask后端序列化问题求助

问题:Flask+React文件上传API报错:TypeError: Object of type Response is not JSON serializable

问题背景

开发Flask+React项目时,API端点负责接收前端上传的.txt文件、运行分析脚本并保存图表,但上传文件时前端出现Axios错误,后端终端抛出TypeError: Object of type Response is not JSON serializable。

错误信息

前端控制台错误

Axios错误截图

后端终端错误

File "/opt/anaconda3/lib/python3.11/json/encoder.py", line 180, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type Response is not JSON serializable

相关代码

后端Flask接口代码

@analysis_ns.route('/upload', methods=["POST", "GET"])
class ChatAnalysisUploadResource(Resource):
    def get(self):
        return {"message": "This endpoint is only for file uploads via POST."}, 405

    #@jwt_required()
    def post(self):
        """Upload a chat file, process it and return the image URLs"""
        try:
            if 'file' not in request.files:
                abort(400, description="No file part")

            file = request.files['file']

            if file.filename == '':
                abort(400, description="No selected file")

            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上传组件代码

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

解决方案

核心原因

Flask-RESTful的Resource类要求返回可序列化的Python字典(或元组),而jsonify()返回的是Flask原生Response对象,无法被Flask-RESTful自动序列化,因此抛出错误。

修改步骤

  1. 后端代码修正:移除所有jsonify()调用,直接返回字典+状态码:

    • 成功响应替换:
      # 原代码:return jsonify(image_urls), 200
      return image_urls, 200
      
    • 异常响应替换:
      # 原代码:return jsonify({"error": str(e)}), 500
      return {"error": str(e)}, 500
      
  2. 前端代码优化:移除手动设置的Content-Type,Axios在传递FormData时会自动添加正确的请求头(包含boundary):

    // 原代码
    const response = await axios.post('http://127.0.0.1:8080/analysis/upload', formData, {
        headers: {
            'Content-Type': 'multipart/form-data'
        }
    });
    // 修改后
    const response = await axios.post('http://127.0.0.1:8080/analysis/upload', formData);
    
  3. 额外检查:确认process_chat_file函数没有返回Response对象,确保它仅执行文件处理逻辑,不返回不可序列化的内容。

修改后,后端可正常序列化响应,前端能正确接收数据并展示结果。


内容的提问来源于stack exchange,提问作者ivanlosarcos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 22:19:50