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
相关产品推荐
相关产品推荐

