无法在FormData

时间:2016-06-05 20:54:38

标签: javascript ajax form-data

我正在使用FormData API。 Here是我正在使用的小提琴 - 我正在尝试将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()现在得到了支持?它似乎适用于非blob?

Firefox 46(在Ubuntu中)

如果FormData()对象未使用已经具有必要文件输入的DOM对象进行初始化(但是已发布附加的正常输入),则似乎不起作用。 FormData.set()似乎不适用于文件输入和blob(您会注意到thumb0在有效负载中为空,尽管在其上调用了fd.set("thumb0", blob, "thumb0.jpg")。您可以通过执行{来验证它是否已设置} {1}}设置完成后,您还会注意到console.log(fd.get("thumb0"))的有效负载错误地是原始图像,而不是调整大小的画布图像。

使用javascript无法自定义多部分image0是不方便的。我是一个javascript noob - 我在这里做了一些完全错误,或者这些浏览器没有正确支持FormData API?如何在我的小提琴中正确提交FormDataimage0

编辑:好的,请给予赏金。我知道有很多依赖于jquery的库,比如blueimp,我认为它们是基于64的数据,而不是作为文件输入传输(加上我想避免使用jquery)。我只需要为这个项目支持最新的Chrome或Firefox,我真的希望我能保持代码干净,因为thumb0 API似乎建议我可以。任何人都可以成功地从画布上获取图像并将其作为文件插入POST有效负载吗?我希望能够在django的FormData中访问它。

2 个答案:

答案 0 :(得分:3)

我认为你在这里缺少的一件事是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出错。加载图像完成后调用它。

你也有多个具有相同身份的元素,

<input id="image0" name="image0" type="file" />
<label for="image0">image0</label> 
<input id="image0" name="thumb0" type="file" />

这不会在您的代码中产生问题,但ID应该是不同的。

<强>更新

这是工作fiddle

注意:将请求网址更改为相应的网址。

请按照以下链接深入了解javascript的异步行为以及如何处理AJAX请求回调。

答案 1 :(得分:1)

通过你的小提琴,你在加载之前清理了dataURL,因此缩略图根本没有加载。 (404)

我做了一个更新的小提琴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,但现在尝试发布到jsfiddle.net上不存在的网址。请在您的环境中试一试。

请注意,html和代码中也有一些其他细微的变化。 (不正确地命名图像,在创建提交的新表单时无需引用现有表格)