如何以 POST 请求的形式上传单独选择的文件? [复制]
Posted
技术标签:
【中文标题】如何以 POST 请求的形式上传单独选择的文件? [复制]【英文标题】:how to upload separately selected files in form POST request? [duplicate] 【发布时间】:2018-07-14 20:08:59 【问题描述】:我想要什么
人们点击添加图片按钮,他们选择一张图片,图片被添加到图库中。
他们可以通过单击叉号删除图像,然后重新单击添加图像按钮以添加更多图像。
这一切都有效,我引用了所有 File
元素。
但是,我不知道如何在表单的 post 请求中发送文件。
问题问题是你不能从文件数组中创建FileList,或者将文件数组设置为input.files = arrOfFiles
。
输入元素本身不允许您添加更多文件或删除文件...它只是用新文件替换旧文件。
这不是我想要的,因此我在 js 中保持对文件对象的引用,并让用户删除图像或添加更多图像。
我知道我可以将单个文件作为 XHR 发送,但我想通过已经存在的表单发送它们。
我想知道一种通过表单而不是js发送文件的方法,但显然这是不可能的
【问题讨论】:
不可能。只需转换为 base 64 并上传到服务器 @MikeMcCaughan 不,那是询问如何通过 ajax 发送数据。我在问如何通过表单发送文件但能够修改它 不清楚您在做什么或为什么...如果您想通过表单发送它们,请使用input type="file"
元素通过表单发送它们。您可以使用 DOM 操作 input
元素的列表。无需将数据加载到 javascript 中。
输入元素允许您选择多个文件,因此如果用户想要删除选择上传的文件中的1个,则没有办法。是的,我只能让用户每次上传选择 1 个文件,并在用户将其从图库中删除时删除该输入元素
【参考方案1】:
这正是 FormData API 的用途:从头开始创建表单数据,您可以将其上传到服务器,就好像它是从 <form>
对象创建的一样,除了您可以控制那里的内容或不是。
所以要在 FormData 中附加一个文件或一个 Blob,代码是
var fd = new FormData();
fd.append(field_name, blob, file_name);
要追加多个文件,您可以再次调用fd.append
,但请注意,后端通常需要将field_name
格式化为他们可以知道此处需要多个值的方式。
通常这是通过在您的字段名后添加[]
来完成的。
var fd = new FormData();
fd.append('files[]', blob_1, file_name_1);
fd.append('files[]', blob_2, file_name_2);
然后您可以通过 AJAX 请求将其发送到您的服务器,这不会影响此请求与由单个 <input multiple name="files[]">
发出的真实请求。
请注意,对于文件,file_name 是可选的,如果未设置,则默认为文件的名称。但是,如果您不想设置随机名称,则 Blob 需要它。
var file_1 = new File(['foo'], 'file1.txt',type:'text/plain');
var file_2 = new File(['bar'], 'file2.txt', type:'text/plain');
var fd = new FormData();
fd.append('files[]', file_1);
fd.append('files[]', file_2);
console.log(...fd.entries());
// and to send it to your server
var xhr = new XMLHttpRequest();
xhr.open('POST', 'your_server_url');
xhr.send(fd);
【讨论】:
所以我想我会拦截表单提交,获取表单数据并将文件添加到表单数据然后发送它,并在发送时重定向到服务器会告诉的任何地方 @MuhammadUmer 就是这样。在表单的submit
事件中,调用event.preventDefault()
,然后构建您的FormData。请注意,如果您的 <form>
中有其他字段,您甚至可以通过调用 new FormData(your_form_element)
让浏览器从当前状态创建 FormData。
@MuhammadUmer 所以再一次快速的谷歌会告诉你输入多个是只读的,如果用户再次选择,则会覆盖。所以kaiido只是告诉你我们大多数人告诉你的。这不可能。你必须自己动手。如何实施取决于您。
@Darkrum 我不确定你来自哪里,但我并不是说不可能,恰恰相反。此外,您似乎弄错了问题:OP 不想拥有一个 <input multipe>
,他希望获得多个 <input>
s,以便他可以使用自己的 UI 处理这些文件。最后,是的you can change the FileList of an input,即使它仍然是一个黑客,FormData 仍然是处理这种情况的最佳方式。
@Darkrum 是的,我明白了。但是,缺少功能。如果它只是安全漏洞,那么你怎么能通过 Ajax 做到这一点,没有意义。但是是的,我明白了,他说的是同样的事情,使用 js 发送文件,并且不能通过表单和 1 个输入元素来完成。但是,我可以使用多个输入并让用户为每个输入选择一个文件,但这会很糟糕【参考方案2】:
如果您只是要上传图片。考虑使用 base64 编码。这就是我所做的。分配 base64 编码的 URL 以对 JSON 进行字符串化,或者您希望对您更容易的任何内容。
当数据被 POST 后,在那里进行转换,以取回您的文件以保存它们。解码 base64 将取决于您在问题中未提及的后端语言。
在 JavaScript 中,您可以使用此函数来加载您提到的处于预览状态的图像。
function previewImage (inputId, eleId)
if (window.FileReader)
var oPreviewImg = null, oFReader = new window.FileReader(),
rFilter = /^(?:image\/bmp|image\/cis\-cod|image\/gif|image\/ief|image\/jpeg|image\/jpeg|image\/jpeg|image\/pipeg|image\/png|image\/svg\+xml|image\/tiff|image\/x\-cmu\-raster|image\/x\-cmx|image\/x\-icon|image\/x\-portable\-anymap|image\/x\-portable\-bitmap|image\/x\-portable\-graymap|image\/x\-portable\-pixmap|image\/x\-rgb|image\/x\-xbitmap|image\/x\-xpixmap|image\/x\-xwindowdump)$/i;
oFReader.onload = function (oFREvent)
if (!oPreviewImg)
var newPreview = document.getElementById(eleId);
oPreviewImg = new Image();
oPreviewImg.style.width = (newPreview.offsetWidth).toString() + "px";
oPreviewImg.style.height = (newPreview.offsetHeight).toString() + "px";
if(newPreview.children.length > 0)
newPreview.replaceChild(oPreviewImg, newPreview.children[0]);
else
newPreview.appendChild(oPreviewImg);
oPreviewImg.src = oFREvent.target.result;
// Add Bootstrap's img-thumbnail class to the image frame
oPreviewImg.classList.add("img-thumbnail");
;
return function ()
var aFiles = document.getElementById(inputId).files;
if (aFiles.length === 0) return;
if (!rFilter.test(aFiles[0].type)) alert("You must select a valid image file!"); return;
oFReader.readAsDataURL(aFiles[0]);
if (navigator.appName === "Microsoft Internet Explorer")
return function ()
document.getElementById(eleId).filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = document.getElementById(inputId).value;
;
然后你可以从img
元素的src
属性中提取base64 URL。
您可能会想出自己喜欢的“取消”上传的方法,可能会破坏 img 元素。
【讨论】:
为什么要改回来?那是资源的浪费。客户可以轻松为您完成。 上传到S3? @Darkrum 如果他想在服务器端用不同的语言用它做任何其他事情。 @MuhammadUmer 从未使用过 S3,因此不确定他们如何处理它。你可以试试。 我的意思是你不会以文本形式将图像上传到s3以上是关于如何以 POST 请求的形式上传单独选择的文件? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
从 Electron 应用程序发出多部分 POST 请求以进行文件上传
aiohttp 异步http请求-4.文件上传multipart/form-data