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

Flask后端文件+JSON上传API:求C#/.NET与Python请求示例

问题:Flask同时上传文件与JSON数据的API请求失败,求正确的C# .NET和Python请求示例

我用Flask搭建了后端服务,创建了可同时上传文件与JSON数据的API接口,并编写了对应的测试函数,但该测试函数无法正常运行。尝试多种方式发送包含文件和JSON数据的请求均失败,请求无法进入后端对应处理页面,收到415(不支持的媒体类型)等错误。现请求提供正确的C# .NET和Python请求示例。


相关代码及报错信息

测试函数

def test_upload_deidentified_file(self, client, headers):
    url = '/upload_deidentified_file'
    file_path = f"{os.path.dirname(os.path.abspath(__file__))}/../../../../files/test_file.mkv"
    with open(file_path, 'rb') as file:
        data = {
            "filename": "test_file.mkv",
            "campaign_name": "Test Campaign Name",
            "session_id": "12345678-1234-1234-1234-123456789123",
            "activity_id": "12345678-1234-1234-1234-123456789123",
            "tags": ["video"],
            "machine_name": "Test Machine Name",
            "creation_date": "2021-01-01",
        }
        file_data = FileStorage(stream=file, filename='test_file.mkv')
        response = client.post(url,
                               data={'json_data': json.dumps(data),
                                     'file': file_data},
                               headers=headers)
    json_data = response.get_json(silent=True)
    logger.info(f"json_data: {json_data}")
    assert response.status_code == HTTPStatus.OK
    assert isinstance(json_data, dict)

后端代码

app = Flask(__name__)
storage_folder = r"path_to_the_storage_folder"


@app.before_request
def before_request():
    message = {
        "remote_address": request.remote_addr,
        "path": request.path,
        "request_method": request.method,
        "headers": request.headers,
        "data": request.data if request.data else None,
        "args": request.args if request.args else None,
        "form": request.form if request.form else None,
        "json": request.json if request.json else None,
    }
    logger.debug(f"Request: {message}")


@app.after_request
def after_request(response):
    message = {
        "remote_address": request.remote_addr,
        "path": request.path,
        "request_method": request.method,
        "status": response.status,
        "response_data": response.data
    }
    logger.debug(f"Response: {message}")
    return response


@app.route('/upload_deidentified_file', methods=['POST'])
def upload_file():
    logger.info('Upload file request received.')
    # 获取请求中的视频文件
    form_data = request.form
    logger.info('表单数据: {}'.format(form_data))
    file = request.files['file']
    logger.info('文件: {}'.format(file))
    return 'OK'


if __name__ == '__main__':
    app.run()

尝试的C# .NET代码及报错

C#代码

// JSON数据
var jsonData = new
{
    filename = "test_file.mkv",
    campaign_name = "Test Project Name",
    session_id = "12345678-1234-1234-1234-123456789123",
    activity_id = "12345678-1234-1234-1234-123456789123",
    tags = new List<string> { "video" },
    machine_name = "Test machine name",
    creation_date = "2021-01-01"
};

using (var httpClient = new HttpClient())
{
    if (headers != null)
    {
        foreach (var header in headers)
        {
            httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
        }
    }

    using (var multipartContent = new MultipartFormDataContent())
    {
        // 添加文件
        var fileStream = File.OpenRead(local_path_for_tests);
        var fileContent = new StreamContent(fileStream);
        multipartContent.Add(fileContent, "file", Path.GetFileName(local_path_for_tests));

        // 添加JSON数据
        var jsonContent = new StringContent(JsonConvert.SerializeObject(jsonData));
        jsonContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
        multipartContent.Add(jsonContent, "json");

        // 发送请求
        using (var response = await httpClient.PostAsync(server_url, multipartContent))
        {
            response.EnsureSuccessStatusCode();
            string responseBody = await response.Content.ReadAsStringAsync();
            Console.WriteLine(responseBody);
        }
    }
}

报错信息

发生异常: CLR/System.Net.Http.HttpRequestException
System.Net.Http.dll中发生了类型为'System.Net.Http.HttpRequestException'的异常,但未在用户代码中处理: '响应状态代码未指示成功: 415 (UNSUPPORTED MEDIA TYPE)。'

尝试的Python代码及报错

Python代码1

# JSON数据
data = {
    'filename': 'test_file.mkv',
    'session_id': session_id,
    'campaign_name': "Test Project Name",
    'activity_id': activity_id,
    'tags': ["video"],
    'machine_name': "Test machine name",
    'creation_date': '2021-01-01'
}

files = {
    'file': open(file_path, 'rb')
}

logger.info(f"向 {url} 发送请求,数据: {data},文件: {files['file'].name}")
start = datetime.now()
response = requests.post(url, data=data, files=files)
logger.info(f"请求耗时: {datetime.now() - start}")
logger.info(f"响应: {response.text}")

报错信息

<!doctype html>
<html lang=en>
<title>415 Unsupported Media Type</title>
<h1>不支持的媒体类型</h1>
<p>未尝试加载JSON数据,因为请求的Content-Type不是'application/json'。</p>

Python代码2

# JSON数据
data = {
    'filename': 'test_file.mkv',
    'session_id': session_id,
    'campaign_name': "Test Project Name",
    'activity_id': activity_id,
    'tags': ["video"],
    'machine_name': "Test machine name",
    'creation_date': '2021-01-01'
}

files = {
    'file': open(file_path, 'rb')
}

headers = {
    'Content-Type': 'application/json'
}

json_data = json.dumps(data)

logger.info(f"向 {url} 发送请求,数据: {data},文件: {files['file'].name}")
start = datetime.now()
response = requests.post(url, headers=headers, data=json_data, files=files)
logger.info(f"请求耗时: {datetime.now() - start}")
logger.info(f"响应: {response.text}")

报错信息

ValueError: Data must not be a string.

正确的请求示例

核心问题说明

Flask后端接口基于multipart/form-data接收数据,请求需以表单形式同时传递文件和JSON字符串(无需单独设置JSON的Content-Type,整体表单格式由框架自动处理)。之前的错误要么是错误设置全局Content-Type为application/json,要么是给表单内的JSON字段设置了独立Content-Type,导致Flask无法正确解析。

正确的Python请求代码

方式1:拆分JSON字段为表单参数

import requests
import json
from datetime import datetime

url = "http://localhost:5000/upload_deidentified_file"
file_path = "path/to/your/test_file.mkv"

# JSON数据拆分后转为表单参数,列表需转为JSON字符串
data = {
    'filename': 'test_file.mkv',
    'session_id': "12345678-1234-1234-1234-123456789123",
    'campaign_name': "Test Project Name",
    'activity_id': "12345678-1234-1234-1234-123456789123",
    'tags': json.dumps(["video"]),
    'machine_name': "Test machine name",
    'creation_date': '2021-01-01'
}

files = {
    'file': open(file_path, 'rb')
}

print(f"向 {url} 发送请求,数据: {data},文件: {files['file'].name}")
start = datetime.now()
response = requests.post(url, data=data, files=files)
print(f"请求耗时: {datetime.now() - start}")
print(f"响应状态码: {response.status_code}")
print(f"响应内容: {response.text}")

files['file'].close()

方式2:传递完整JSON字符串字段(与测试函数逻辑一致)

import requests
import json
from datetime import datetime

url = "http://localhost:5000/upload_deidentified_file"
file_path = "path/to/your/test_file.mkv"

# 完整JSON数据
json_data = {
    "filename": "test_file.mkv",
    "campaign_name": "Test Campaign Name",
    "session_id": "12345678-1234-1234-1234-123456789123",
    "activity_id": "12345678-1234-1234-1234-123456789123",
    "tags": ["video"],
    "machine_name": "Test Machine Name",
    "creation_date": "2021-01-01",
}

files = {
    'file': open(file_path, 'rb')
}

# 将JSON转为字符串作为表单字段传递
data = {
    'json_data': json.dumps(json_data)
}

print(f"向 {url} 发送请求,JSON数据: {json_data},文件: {files['file'].name}")
start = datetime.now()
response = requests.post(url, data=data, files=files)
print(f"请求耗时: {datetime.now() - start}")
print(f"响应状态码: {response.status_code}")
print(f"响应内容: {response.text}")

files['file'].close()

正确的C# .NET请求代码

using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using Newtonsoft.Json;

class Program
{
    static async System.Threading.Tasks.Task Main(string[] args)
    {
        string server_url = "http://localhost:5000/upload_deidentified_file";
        string local_path_for_tests = @"path\to\your\test_file.mkv";

        // JSON数据
        var jsonData = new
        {
            filename = "test_file.mkv",
            campaign_name = "Test Project Name",
            session_id = "12345678-1234-1234-1234-123456789123",
            activity_id = "12345678-1234-1234-1234-123456789123",
            tags = new List<string> { "video" },
            machine_name = "Test machine name",
            creation_date = "2021-01-01"
        };

        using (var httpClient = new HttpClient())
        {
            using (var multipartContent = new MultipartFormDataContent())
            {
                // 添加文件
                using (var fileStream = File.OpenRead(local_path_for_tests))
                {
                    var fileContent = new StreamContent(fileStream);
                    multipartContent.Add(fileContent, "file", Path.GetFileName(local_path_for_tests));
                }

                // 将JSON转为字符串作为表单字段传递,无需设置单独Content-Type
                var jsonString = JsonConvert.SerializeObject(jsonData);
                multipartContent.Add(new StringContent(jsonString), "json_data");

                // 发送请求
                using (var response = await httpClient.PostAsync(server_url, multipartContent))
                {
                    Console.WriteLine($"响应状态码: {response.StatusCode}");
                    string responseBody = await response.Content.ReadAsStringAsync();
                    Console.WriteLine($"响应内容: {responseBody}");
                }
            }
        }
    }
}

后端代码调整(可选)

如果要接收完整JSON字段,可在后端解析json_data:

import json

@app.route('/upload_deidentified_file', methods=['POST'])
def upload_file():
    logger.info('Upload file request received.')
    # 获取表单中的JSON字符串并解析
    json_str = request.form.get('json_data')
    if json_str:
        json_data = json.loads(json_str)
        logger.info('解析后的JSON数据: {}'.format(json_data))
    # 获取文件
    file = request.files['file']
    logger.info('文件: {}'.format(file))
    return 'OK'

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 11:59:56