无法在 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 中正确提交 image0thumb0


编辑:好的,去悬赏这个。我知道那里有像 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 请求回调。