我有两个文件输入和按钮。按下按钮时,它应该将两个文件发送到服务器并等待接收文件(两个文件在服务器端处理并返回结果)。
.HTML
<input id='file-input1' type='file'>
<input id='file-input2' type='file'>
<button id='send-btn'>
JavaScript (客户端)
var input1 = document.getElementById('file-input1');
var input2 = document.getElementById('file-input2');
var btn = document.getElementById('send-btn');
var file1 = null;
var file2 = null;
input1.addEventListener('change', () => file1 = input1.files[0]);
input2.addEventListener('change', () => file2 = input2.files[0]);
btn.addEventListener('click', () => {
if (file1 === null || file2 === null) return;
_sendfiles(file1, file2);
});
function _sendfiles(file1, file2) {
let xmlhttp = new XMLHttpRequest();
xml.open("PUT", "/process", true);
xmlhttp.send({'file1': file1, 'file2': file2});
}
JavaScript (服务器)
app.put('/process', (req, res) => {
// Get files from request
// Do stuff with them to generate a third file
// Send generated file back
});
我不确定如何在服务器端接收文件,也不确定如何在客户端等待接收服务器的文件。不鼓励使用第三方模块,但并非完全不可能。我也没有嫁给使用XMLHttpRequest()
的想法.
为了方便起见,我建议使用Fetch
+FormData
API:
const formData = new FormData()
formData.append('file1', file1)
formData.append('file2', file2)
fetch(`/api/companies/${id}/logo`, {
method: 'PUT',
body: formData
})
将实例传递给body
FormData
将自动设置Content-Type: multipart/form-data
标头。
在服务器端,我建议使用multer
,因为您已经使用了express
。当然,如果需要,您可以实现自己的中间件来从请求流中检索文件(我自己没有这样做,所以帮不上什么忙)。
要在客户端上接收文件,您可以执行以下操作(我假设您希望将此文件下载到用户的文件系统):
方式#1(简单):
在响应中,只需发送此文件的下载URL。然后使用此解决方案创建一个链接并在其上触发click
事件。该文件将由浏览器下载。
方式#2(不是那么简单):
在服务器上使用res.sendFile
方法发送文件(如果它位于 fs 上 - 否则您可以发送这样的文件缓冲区)。
然后在客户端上,可以使用response.blob()
方法来访问文件 Blob。 使用类似的技巧URL.createObjectURL
借助 API 将此 blob 下载到文件中。
此外,Response
API 允许您通过管道传输流并在需要时对其进行其他操作(请参阅Streams API
)。
编辑(最简单的方法)
正如Endless指出的那样,实际上有一种更简单的方法。我想我花了太多时间处理 AJAX 请求...🤷♂️
您可以通过单击submit
按钮提交您的 HTML 表单,这样浏览器将自动发送带有Content-Type: multipart/form-data
的 POST(是的,不能以这种方式进行 PUT )请求,因为您的输入类型为file
:
<form method='post' action='/process'>
<input name='file1' type='file'>
<input name='file2' type='file'>
<button type='submit'>Submit</button>
</form>
因此,实际上无需设置任何事件侦听器或使用任何JS。
然后在服务器上使用res.sendFile
并添加一个Content-Disposition: attachment; filename="filename.jpg"
标头,以确保浏览器将其作为附件下载,而不是将其作为网页打开。
这里最大的缺点是浏览器中没有内置的便捷方法来订阅请求的完成事件。 也就是说,form
上没有您可以收听的success
事件。
因此,如果您需要它,那么一个不错的方法是从服务器发送cookie以及文件。 在客户端上,在您提交表单的那一刻设置一个间隔,并在那里检查cookie是否存在。如果存在,则表示文件已下载。