假设我在页面上有这个元素:
<input id="image-file" type="file" />
这将创建一个按钮,允许网页用户通过浏览器中的操作系统“文件打开...”对话框选择文件。
假设用户单击所述按钮,在对话框中选择一个文件,然后单击“确定”按钮关闭对话框。
选定的文件名现在存储在:
document.getElementById("image-file").value
现在,假设服务器在 URL“/upload/image”处处理多部分 POST。
如何将文件发送到“/upload/image”?
另外,我如何收听文件上传完成的通知?
纯JS
您可以选择将 fetch 与 await-try-catch 一起使用
let photo = document.getElementById("image-file").files[0];
let formData = new FormData();
formData.append("photo", photo);
fetch('/upload/image', {method: "POST", body: formData});
异步函数 SavePhoto(inp) { let user = { name:'john', age:34 };让 formData = new FormData();让照片 = inp.files[0]; formData.append("照片", 照片); formData.append("用户", JSON.stringify(user)); const ctrl = new AbortController() // 超时 setTimeout(() => ctrl.abort(), 5000);尝试 { let r = await fetch('/upload/image', {method: "POST", body: formData, signal: ctrl.signal}); console.log('HTTP响应码:',r.status); } catch(e) { console.log('休斯顿我们有问题...:', e); } }
在选择文件之前打开 chrome 控制台 > 网络选项卡以查看请求详细信息。
因为在这个例子中我们向 https://stacksnippets.net/upload/image 发送请求,所以响应代码将是 404 ofcourse...
(在堆栈溢出片段存在错误处理问题,但是在 jsfiddle 版本 中,404 错误 4xx/5xx 是 不抛出但我们可以读取包含代码的响应状态)
老派方法 - xhr
let photo = document.getElementById("image-file").files[0]; // file from input
let req = new XMLHttpRequest();
let formData = new FormData();
formData.append("photo", photo);
req.open("POST", '/upload/image');
req.send(formData);
function SavePhoto(e) { let user = { name:'john', age:34 };让 xhr = new XMLHttpRequest();让 formData = new FormData();让照片 = e.files[0]; formData.append("用户", JSON.stringify(user)); formData.append("照片", 照片); xhr.onreadystatechange = state => { console.log(xhr.status); } // 错误处理 xhr.timeout = 5000; xhr.open("POST", '/upload/image'); xhr.send(formData); }
选择文件并打开 chrome 控制台 > 网络选项卡以查看请求详细信息。
因为在本例中,我们将请求发送到 https://stacksnippets.net/upload/image,所以响应代码将是 404 ofcourse...
(堆栈溢出片段,在错误处理方面存在一些问题 - xhr.status 为零(而不是 404),这类似于我们从 本地光盘 - 所以我还提供了 js fiddle 版本,它显示了正确的 http 错误代码 这里 )
概括
在服务器端,您可以读取原始文件名(和其他信息),这些文件名自动包含在文件名 formData 参数中的浏览器请求中。
您不需要将请求标头 Content-Type 设置为 multipart/form-data - 这将由浏览器自动设置(包括强制边界参数)。
而不是 /upload/image 你可以使用像 http://.../upload/image 这样的完整地址(当然这两个地址都是任意的,并且取决于服务器 - 与参数方法相同的情况 - 通常在服务器上使用“POST”用于文件上传,但有时可以使用“PUT”或其他)。
如果您想在单个请求中发送多个文件,请使用多个属性:,并以类似的方式将所有选择的文件附加到 formData(例如 photo2=...files[2];... formData.append("photo2", photo2);)
您可以包含附加数据(json)以请求例如 let user = {name:'john', age:34} 以这种方式: formData.append("user", JSON.stringify(user));
您可以设置超时:使用 AbortController 获取,旧方法通过 xhr.timeout=milisec
此解决方案应适用于所有主要浏览器。
除非您尝试使用 ajax 上传文件,否则只需提交表单到 /upload/image
。
<form enctype="multipart/form-data" action="/upload/image" method="post">
<input id="image-file" type="file" />
</form>
如果您确实想在后台上传图片(例如,不提交整个表单),您可以使用 ajax:
使用jsp和javascript进行异步文件上传(AJAX文件上传)
jQuery Ajax 文件上传
Ajax 使用文件上传
我一直在尝试这样做一段时间,但这些答案都不适合我。我就是这样做的。
我有一个选择文件和一个提交按钮
<input type="file" name="file" id="file">
<button onclick="doupload()" name="submit">Upload File</button>
然后在我的javascript代码中我把这个
function doupload() {
let data = document.getElementById("file").files[0];
let entry = document.getElementById("file").files[0];
console.log('doupload',entry,data)
fetch('uploads/' + encodeURIComponent(entry.name), {method:'PUT',body:data});
alert('your file has been uploaded');
location.reload();
};
如果你喜欢 StackSnippets...
函数 doupload() { 让数据 = document.getElementById("file").files[0];让 entry = document.getElementById("file").files[0]; console.log('doupload',entry,data) fetch('uploads/' + encodeURIComponent(entry.name), {method:'PUT',body:data}); alert('您的文件已上传'); };
PUT
方法与 POST
方法略有不同。在这种情况下,在 chrome 的 Web 服务器中,POST
方法未实现。
用 chrome 的网络服务器测试 - https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb?hl=en
注意 - 使用 chrome 的 Web 服务器时,您需要进入高级选项并选中“启用文件上传”选项。如果你不这样做,你会得到一个不允许的错误。
enctype="multipart/form-data"
net::ERR_ABORTED 405 (Method Not Allowed)
POST http://localhost:8000/upload/image 404 (Not Found)
。在我的 React Node 测试项目的 /src 和 /public 下创建 /upload/image。