无法在 FormData 中发送 blob 负载
Unable to send blob payload in FormData
我正在玩 FormData
API。 Here 是我正在使用的 fiddle - 我正在尝试将 blob 注入我的表单并通过 AJAX.
提交
//ic0 and tc0 are canvases
//image0 and thumb0 are file inputs
function ajaxSubmit(){
var fd = new FormData(document.forms[0]);
ic0.toBlob(
function(blob){
fd.set("image0", blob, "image0.jpg");
}, "image/jpeg", 0.7);
tc0.toBlob(
function(blob){
fd.set("thumb0", blob, "thumb0.jpg");
}, "image/jpeg", 0.7);
var xhr = new XMLHttpRequest();
xhr.open("POST", "/ajax-upload/", true);
xhr.send(fd);
}
浏览器行为有点...奇怪:
Chrome 50(在Ubuntu)
做不到,给出:
Failed blob:https%3A//fiddle.jshell.net/uuid4 to load resource: the server responded with 404
但我认为现在支持 FormData.set()
?它似乎适用于非斑点?
Firefox 46(在 Ubuntu 中)
如果 FormData()
对象未使用已经具有必要文件输入的 DOM 对象初始化(但是附加的正常输入已发布),则
似乎不起作用。 FormData.set()
似乎不适用于文件输入和 blob(您会注意到 thumb0
在有效负载中为空,尽管在其上调用了 fd.set("thumb0", blob, "thumb0.jpg")
。您可以通过执行 fd.set("thumb0", blob, "thumb0.jpg")
来验证它是否已设置=18=] 就在设置之后。您还会注意到 image0
的负载不正确地是您的原始图像,而不是调整大小后的 canvas 图像。
无法使用 javascript 自定义多部分 FormData
,这很不方便。我是一个 javascript 菜鸟 - 我只是在这里做错了什么,还是这些浏览器没有正确支持 FormData
API?如何在 fiddle 中正确提交 image0
和 thumb0
?
编辑:好的,去悬赏这个。我知道那里有像 blueimp 这样的依赖 jquery 的大库,我认为它们对数据进行 base64,而不是作为文件输入传输(另外我想避免 jquery)。我只需要为这个项目支持最新的 Chrome 或 Firefox,我真的希望我能保持代码像 FormData
API 似乎暗示的那样干净.任何人都可以成功地从 canvas 中抓取图像并将其作为文件插入到 POST 负载中吗?我希望能够在 django 的 request.FILES
中访问它。
查看您的 fiddle,您在加载之前清理了 dataURL,因此根本没有加载缩略图。 (404)
我更新了 fiddle https://jsfiddle.net/tLqch5x2/3/
function handleFiles(e){
var img = new Image();
img.onload = function(){
var width = 30;
var height = img.height * 30/img.width;
e.target.ic0.width = width ;
e.target.ic0.height = height ;
e.target.tc0.width = width/2 ;
e.target.tc0.height = height/2;
var ctx = e.target.ic0.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);
ctx = e.target.tc0.getContext("2d");
ctx.drawImage(img, 0, 0, width/2, height/2);
URL.revokeObjectURL(img.src); //clean up memory here instead
};
img.src = URL.createObjectURL(e.target.files[0]);
//clean up to prevent memory leak
//URL.revokeObjectURL(img.src); //too soon
}
它仍然有一个 404,但现在从尝试 post 到 url jsfiddle.net 上不存在的 url。请在您的环境中试一试。
请注意,html 和代码中还有一些其他的小改动。 (图片命名不当,创建新表单提交时无需引用已有表单)
我认为您在这里遗漏的一件事是 javascript 的异步特性。在您的 ajaxSubmit
方法中 -
function ajaxSubmit(){
var fd = new FormData(document.forms[0]);
ic0.toBlob(function(blob){
fd.set("image0", blob, "image0.jpg");
}, "image/jpeg", 0.7); // this call is asynchronous
tc0.toBlob(function(blob){
fd.set("thumb0", blob, "thumb0.jpg");
}, "image/jpeg", 0.7); // this call is also asynchronous
/*
hence the below code may get executed before
fd.set("image0", blob, "image0.jpg");
this statement. which it does.
that is why the canvas files are not submitted.
*/
var xhr = new XMLHttpRequest();
xhr.open("POST", "/ajax-upload/", true);
xhr.send(fd);
}
尝试像这样同步代码
function ajaxSubmit(){
var fd = new FormData(document.forms[0]);
ic0.toBlob(function(blob){
fd.set("image0", blob, "image0.jpg");
tc0.toBlob(function(blob){
fd.set("thumb0", blob, "thumb0.jpg");
console.log(blob);
console.log("Just blobbed thumb0");
var xhr = new XMLHttpRequest();
xhr.open("POST", "fileuploadbackend.jsp", true);
//xhr.setRequestHeader("X-CSRFToken", csrftoken);
xhr.send(fd);
}, "image/jpeg", 0.7);
}, "image/jpeg", 0.7);
}
也正如 jornare 建议您应该注释掉行
URL.revokeObjectURL(img.src);
导致 chrome 出错。图片加载完成后调用
您还有多个具有相同 ID 的元素,
<input id="image0" name="image0" type="file" />
<label for="image0">image0</label>
<input id="image0" name="thumb0" type="file" />
这不会在您的代码中造成问题,但 ID 应该不同。
更新
这是工作 fiddle。
注意:将请求url改为你对应的url。
点击这些链接可以更深入地了解 javascript 的异步行为以及如何处理 AJAX 请求回调。
- How does Asynchronous Javascript Execution happen
- Developer Mozilla - Synchronous and asynchronous requests
- How does javascript handle AJAX request in background.
我正在玩 FormData
API。 Here 是我正在使用的 fiddle - 我正在尝试将 blob 注入我的表单并通过 AJAX.
//ic0 and tc0 are canvases
//image0 and thumb0 are file inputs
function ajaxSubmit(){
var fd = new FormData(document.forms[0]);
ic0.toBlob(
function(blob){
fd.set("image0", blob, "image0.jpg");
}, "image/jpeg", 0.7);
tc0.toBlob(
function(blob){
fd.set("thumb0", blob, "thumb0.jpg");
}, "image/jpeg", 0.7);
var xhr = new XMLHttpRequest();
xhr.open("POST", "/ajax-upload/", true);
xhr.send(fd);
}
浏览器行为有点...奇怪:
Chrome 50(在Ubuntu)
做不到,给出:
Failed blob:https%3A//fiddle.jshell.net/uuid4 to load resource: the server responded with 404
但我认为现在支持 FormData.set()
?它似乎适用于非斑点?
Firefox 46(在 Ubuntu 中)
如果 FormData()
对象未使用已经具有必要文件输入的 DOM 对象初始化(但是附加的正常输入已发布),则
似乎不起作用。 FormData.set()
似乎不适用于文件输入和 blob(您会注意到 thumb0
在有效负载中为空,尽管在其上调用了 fd.set("thumb0", blob, "thumb0.jpg")
。您可以通过执行 fd.set("thumb0", blob, "thumb0.jpg")
来验证它是否已设置=18=] 就在设置之后。您还会注意到 image0
的负载不正确地是您的原始图像,而不是调整大小后的 canvas 图像。
无法使用 javascript 自定义多部分 FormData
,这很不方便。我是一个 javascript 菜鸟 - 我只是在这里做错了什么,还是这些浏览器没有正确支持 FormData
API?如何在 fiddle 中正确提交 image0
和 thumb0
?
编辑:好的,去悬赏这个。我知道那里有像 blueimp 这样的依赖 jquery 的大库,我认为它们对数据进行 base64,而不是作为文件输入传输(另外我想避免 jquery)。我只需要为这个项目支持最新的 Chrome 或 Firefox,我真的希望我能保持代码像 FormData
API 似乎暗示的那样干净.任何人都可以成功地从 canvas 中抓取图像并将其作为文件插入到 POST 负载中吗?我希望能够在 django 的 request.FILES
中访问它。
查看您的 fiddle,您在加载之前清理了 dataURL,因此根本没有加载缩略图。 (404)
我更新了 fiddle https://jsfiddle.net/tLqch5x2/3/
function handleFiles(e){
var img = new Image();
img.onload = function(){
var width = 30;
var height = img.height * 30/img.width;
e.target.ic0.width = width ;
e.target.ic0.height = height ;
e.target.tc0.width = width/2 ;
e.target.tc0.height = height/2;
var ctx = e.target.ic0.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);
ctx = e.target.tc0.getContext("2d");
ctx.drawImage(img, 0, 0, width/2, height/2);
URL.revokeObjectURL(img.src); //clean up memory here instead
};
img.src = URL.createObjectURL(e.target.files[0]);
//clean up to prevent memory leak
//URL.revokeObjectURL(img.src); //too soon
}
它仍然有一个 404,但现在从尝试 post 到 url jsfiddle.net 上不存在的 url。请在您的环境中试一试。
请注意,html 和代码中还有一些其他的小改动。 (图片命名不当,创建新表单提交时无需引用已有表单)
我认为您在这里遗漏的一件事是 javascript 的异步特性。在您的 ajaxSubmit
方法中 -
function ajaxSubmit(){
var fd = new FormData(document.forms[0]);
ic0.toBlob(function(blob){
fd.set("image0", blob, "image0.jpg");
}, "image/jpeg", 0.7); // this call is asynchronous
tc0.toBlob(function(blob){
fd.set("thumb0", blob, "thumb0.jpg");
}, "image/jpeg", 0.7); // this call is also asynchronous
/*
hence the below code may get executed before
fd.set("image0", blob, "image0.jpg");
this statement. which it does.
that is why the canvas files are not submitted.
*/
var xhr = new XMLHttpRequest();
xhr.open("POST", "/ajax-upload/", true);
xhr.send(fd);
}
尝试像这样同步代码
function ajaxSubmit(){
var fd = new FormData(document.forms[0]);
ic0.toBlob(function(blob){
fd.set("image0", blob, "image0.jpg");
tc0.toBlob(function(blob){
fd.set("thumb0", blob, "thumb0.jpg");
console.log(blob);
console.log("Just blobbed thumb0");
var xhr = new XMLHttpRequest();
xhr.open("POST", "fileuploadbackend.jsp", true);
//xhr.setRequestHeader("X-CSRFToken", csrftoken);
xhr.send(fd);
}, "image/jpeg", 0.7);
}, "image/jpeg", 0.7);
}
也正如 jornare 建议您应该注释掉行
URL.revokeObjectURL(img.src);
导致 chrome 出错。图片加载完成后调用
您还有多个具有相同 ID 的元素,
<input id="image0" name="image0" type="file" />
<label for="image0">image0</label>
<input id="image0" name="thumb0" type="file" />
这不会在您的代码中造成问题,但 ID 应该不同。
更新
这是工作 fiddle。
注意:将请求url改为你对应的url。
点击这些链接可以更深入地了解 javascript 的异步行为以及如何处理 AJAX 请求回调。
- How does Asynchronous Javascript Execution happen
- Developer Mozilla - Synchronous and asynchronous requests
- How does javascript handle AJAX request in background.