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

从JS向Python CGI上传文件始终返回空字典问题

问题根源
  • File对象无法JSON序列化:JSON.stringify不支持处理File类型数据,会将其转为空对象{},导致服务器接收不到文件内容。
  • 请求格式不匹配:手动设置Content-type: application/json,但文件上传需要用表单默认的multipart/form-data编码,两种格式的处理逻辑完全不同。
修复步骤

1. 修改JavaScript代码

直接发送FormData对象(无需转为JSON),移除手动设置的Content-type头(浏览器会自动为FormData设置正确的multipart/form-data头及边界标识):

async function addFile() {
  const formData = new FormData(document.forms["DataForm"]);
  
  function handleFileUpload(fileInputId) {
    console.log("uploading file...");
    const fileInput = document.getElementById(fileInputId);
    const file = fileInput.files[0];

    if (!file) {
      console.log("No file selected");
      return false;
    }

    // 验证PDF格式和10MB大小限制
    if (file.type !== "application/pdf") {
      alert("请上传PDF格式文件");
      return false;
    }
    const maxSize = 10 * 1024 * 1024; // 10MB
    if (file.size > maxSize) {
      alert("文件大小不能超过10MB");
      return false;
    }

    console.log(`filesize = ${file.size}`);
    return true;
  }

  if (!handleFileUpload("file_contract")) {
    console.log("form submission prevented");
    return false;
  }

  try {
    const response = await fetch("../../cgi-bin/addRecord.py", {
      method: "POST",
      body: formData,
    });

    const responseData = await response.json();

    if (responseData.hasOwnProperty("status")) {
      if (responseData["status"] === "failed") {
        alert("Login sessie vervallen. Log opnieuw in.");
      } else if (responseData.status === "success") {
        const host = window.location.host;
        const redirectUrl = `http://${host}`;
        console.log("redirecting... (commented out)");
        // window.location.replace(redirectUrl);
      } else {
        alert("Fout bij het opslaan. Probeer het nog eens of contacteer Sandra.");
      }
    }
  } catch (error) {
    console.error(error);
    alert("Fout bij het opslaan. Probeer het nog eens of contacteer Sandra.");
  }
}

2. 修改Python CGI代码

使用cgi模块解析multipart/form-data格式的表单数据,和表单直接提交的处理逻辑保持一致:

#!/usr/bin/env python3

import cgi
import hashlib
import json
import os
import logging

# Get the absolute path of the current script
dirname = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

if os.path.exists(f'{dirname + "/log.log"}'):
    with open(f'{dirname + "/log.log"}', 'w'):
        pass

logging.basicConfig(filename=f'{dirname + "/log.log"}', level=logging.DEBUG)


def generate_response(status, data=None):
    response = {"status": status}
    if data:
        response["data"] = data

    print("Content-Type: application/json")
    print()
    print(json.dumps(response))


def calculate_file_hash(file_data):
    md5_hash = hashlib.md5()
    for chunk in iter(lambda: file_data.read(4096), b''):
        md5_hash.update(chunk)
    return md5_hash.hexdigest()


def main():
    try:
        # 解析multipart/form-data格式的表单数据
        form = cgi.FieldStorage()
        
        if "file_contract" in form:
            contract_file = form["file_contract"]
            # 确认是文件上传
            if contract_file.file:
                contract_file_filename = contract_file.filename
                contract_file_hash = calculate_file_hash(contract_file.file)
                # 重置文件指针到开头(计算哈希时已读取过一次)
                contract_file.file.seek(0)
                
                contract_filename_path = os.path.join(dirname, "documenten", contract_file_hash)
                with open(contract_filename_path, 'wb') as contract_file_handle:
                    contract_file_handle.write(contract_file.file.read())
        
        generate_response("success")
    except Exception as e:
        logging.error(str(e))
        generate_response("failed")


if __name__ == "__main__":
    main()

额外说明

  • 直接表单提交正常的原因:表单默认使用multipart/form-data编码,cgi.FieldStorage可以正确解析文件;而JS转JSON发送时,File对象被序列化为空对象,服务器无法获取有效数据。
  • 验证逻辑保留:JS中的PDF格式和大小检查依然生效,确保不符合要求的文件不会被发送到服务器。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 19:01:27