Flask多图上传删除后提交异常:NS_binding aborted错误排查
Flask多图上传问题修复:仅获取最后一张图片及NS_binding aborted错误解决
问题概述
开发网站时,用户可多次上传、删除图片,通过uploadedPhotos数组维护图片列表,但提交表单后后端仅能获取最后一次上传的图片,且浏览器出现NS_binding aborted网络错误,开发环境使用HTTP。
核心问题原因
- 重复请求导致中断:前端同时调用
sendPhotosToServer()(Fetch请求)和form.submit()(原生表单提交),触发两次POST请求,浏览器主动中断第一个请求引发NS_binding aborted错误。 - 前后端键名不匹配:前端Fetch请求中用
photo_${index}作为图片字段名,但后端用request.files.getlist('photo')获取,无法匹配所有图片。 - 原生表单未包含全部图片:原生表单提交时,file控件仅保留最后一次选择的文件,
uploadedPhotos中的历史图片未被加入表单提交数据。
分步解决方案
1. 移除重复提交,统一用Fetch处理
删除原生表单提交逻辑,仅通过Fetch提交所有数据,避免重复请求:
form.addEventListener( "submit", async function (event) { event.preventDefault(); if (!form.checkValidity()) { form.classList.add("was-validated"); } else { if (confirm("Are you sure you want to post the ad?")) { const success = await sendPhotosToServer(); if (success) { // 上传成功后跳转首页 window.location.href = "/"; } } } }, false );
2. 统一FormData字段名,兼容后端获取逻辑
将所有图片统一用photo作为字段名追加到FormData,同时保留原生表单的其他字段:
async function sendPhotosToServer() { const formData = new FormData(form); // 先获取表单已有字段 // 追加所有维护的图片,统一用`photo`作为键名 uploadedPhotos.forEach((photo) => { formData.append("photo", photo); }); try { const response = await fetch(`/post-ads/${category}/${subcategory}`, { method: "POST", body: formData, }); if (response.ok) { const result = await response.json(); console.log("Photos uploaded successfully!", result); return true; } else { console.log("Failed to upload photos.", response.status); return false; } } catch (error) { console.error("Error during photo upload:", error); console.log("An error occurred while uploading photos."); return false; } }
3. 修复后端逻辑,正确处理文件并返回JSON
修正后端语法错误,同时注意不能直接将File对象存入数据库,需先保存到服务器再存储路径:
from flask import jsonify from werkzeug.utils import secure_filename import os import json @postAd.route("/post-ads/<category>/<subcategory>", methods=['GET','POST']) @login_required def post_ad(category,subcategory): if request.method == 'POST': photos = request.files.getlist('photo') photo_paths = [] # 保存图片到服务器 for photo in photos: if photo.filename.strip() != '': filename = secure_filename(photo.filename) # 确保uploads目录存在 upload_dir = os.path.join(app.root_path, 'uploads') os.makedirs(upload_dir, exist_ok=True) save_path = os.path.join(upload_dir, filename) photo.save(save_path) photo_paths.append(filename) # 将路径列表序列化后存入数据库(需确保Ad模型的photos字段支持字符串存储) ad = Ad(photos=json.dumps(photo_paths)) db.session.add(ad) db.session.commit() flash('发布广告成功!','success') return jsonify({"status": "success", "message": "广告发布完成"}) return render_template("postAd.html", category=category, subcategory=subcategory)
4. 修复删除逻辑的索引匹配问题
原删除逻辑用indexOf可能因为File对象引用问题找不到正确索引,改用唯一ID标识:
function handleImageUpload(e) { const files = Array.from(e.target.files); files.forEach((file) => { // 生成唯一ID标识文件 const fileUniqueId = Date.now() + Math.random().toString(36).slice(2); file._uniqueId = fileUniqueId; uploadedPhotos.push(file); const picReader = new FileReader(); picReader.addEventListener("load", (event) => { const imgContainer = document.createElement("div"); imgContainer.className = "col"; imgContainer.dataset.fileId = fileUniqueId; // 将ID绑定到DOM元素 imgContainer.innerHTML = ` <div class="card"> <div class="image-container"> <img src="${event.target.result}" alt="${file.name}" class="card-img-top" style="height: 200px;object-fit: cover;"> </div> <div class="card-body"> <button class="btn btn-danger btn-sm delete-btn">Delete</button> </div> </div> `; const deleteBtn = imgContainer.querySelector(".delete-btn"); deleteBtn.addEventListener("click", () => { imgContainer.remove(); // 通过唯一ID查找并删除数组中的对应文件 const index = uploadedPhotos.findIndex(item => item._uniqueId === fileUniqueId); if (index > -1) { uploadedPhotos.splice(index, 1); } }); output.appendChild(imgContainer); }); picReader.readAsDataURL(file); }); }
内容的提问来源于stack exchange,提问作者kevin
相关产品推荐
相关产品推荐

