Locust编写文件上传压测任务时报400错误的问题排查
故障定位与修正方案
核心问题点
- 最核心触发报错的原因:手动硬编码
multipart/form-data的边界值、Content-Length请求头。Locust底层基于requests库实现请求,当同时传递表单字段data和文件参数files时,库会自动生成与实际请求体完全匹配的边界标识、计算准确的请求体长度;手动写死的参数和实际发送的报文不匹配,会导致服务端解析表单时出现流截断,直接触发“Unexpected end of Stream”的报错。 - 表单字段值中的
"是HTML转义的双引号字符,实际传递给后端的内容不是预期的JSON结构,会造成字段校验异常。 - 本地打开的文件句柄没有做自动释放处理,高并发场景下会出现文件读取不全、请求流不完整的问题。
修正后的可运行代码
from locust import task, HttpUser class FileUploadTask(HttpUser): @task def constraintsuploaddoc(self): # 移除手动硬编码的content-type、content-length头,交由底层请求库自动生成 headersc = { 'Accept-Encoding': 'gzip, deflate, br', 'Accept': '*/*' } # 替换HTML转义字符为正常双引号,保证blobText为合法JSON结构 payload = { 'blobText': '{"ID": 3, "FileClass": "LogicsticsConstraints", "FileDescriptor": "test", "FieldName": "lookup.csv"}' } # 使用上下文管理器打开文件,自动释放文件句柄 with open(r"C:\Perffiles\lookup.csv", "rb") as file_handle: files = [ ('File', ('lookup.csv', file_handle, 'text/csv')) ] rupload = self.client.put( "/api/v1/FileUpload/Upload", data=payload, files=files, verify=False, headers=headersc, name="constraintsuploaddoc" ) if rupload.status_code == 200: rupload.success() else: rupload.failure(f"上传失败,状态码{rupload.status_code},返回详情:{rupload.text}")
压测优化注意事项
- 带文件上传的请求中,绝对不要手动指定
Content-Type为multipart/form-data,也不要硬编码边界值,否则会100%出现表单解析失败的问题。 - 测试用的文件内容建议在任务初始化阶段就预加载到内存,避免每次请求都执行磁盘IO、反复开关文件句柄,既可以提升压测场景的并发性能,也能规避文件读取不完整的异常。
- 如需自定义请求边界值,必须保证边界标识和组装出来的请求体完全匹配,否则服务端无法正确拆分多表单结构。
内容的提问来源于stack exchange,提问作者Nagarjuna Pillappa
相关产品推荐
相关产品推荐

