【问题标题】:XMLHttpRequest post multipart FormData, file gets added twiceXMLHttpRequest 发布多部分 FormData,文件被添加两次
【发布时间】:2018-02-12 14:05:29
【问题描述】:

我正在使用 XMLHttpRequest 和 FormData 制作上传机制。但是,在创建请求时,文件以某种方式被添加了两次,我在这里缺少什么?

我有一个类 Uploader 负责提交多部分表单,一个静态对象 cc 负责实际上传。

Uploader-class 的上传方法是在单个输入字段调度 change 事件时从 JS 调用的。

Uploader 类如下所示:

class Uploader {
    constructor(form){
        this._form = form;
        this._files = [];
    }

    _buildFileIndex(){
        const fileInputsEl = this._form.querySelectorAll('input[type="file"]');
        const fileInputs = Array.from(fileInputsEl).map(input => {
            return {
                'name': input.getAttribute('name') || 'undefined',
                'files': input.files
            }
        });

        this._fileInputs = fileInputs;
        return fileInputs;
    }

    _buildFormData(){
        this._formData = new FormData(this._form);
        for(let input of this._fileInputs){
            for(let file of input.files){
                this._formData.append(input.name, file, file.name);
            }
        }

        return this._formData;
    }

    upload(callback){
        this._buildFileIndex();
        this._buildFormData();

        cc.POST('/api/upload', this._formData, res => {
            if(typeof callback === 'function') callback(res);
        });
    }
}

cc 对象:

const cc = {
    'serverADDR': function(){return window.location.protocol + '//' + window.location.host},
    'POST': function(endpoint, data, callback, contentType){
        const xhttp = new XMLHttpRequest();
        xhttp.open('POST', cc.serverADDR() + endpoint, true);

        if(contentType) xhttp.setRequestHeader('Content-Type', contentType);

        xhttp.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                if(typeof callback === 'function') callback(this);
            }
        };

        xhttp.send(data);
    }
}

这是根据谷歌浏览器发送的数据,当一个输入只选择一个文件时:

------WebKitFormBoundaryEDgRU4CNKJQjnIA8
Content-Disposition: form-data; name="media"; filename="Skärmavbild 2017-10-29 kl. 12.16.50.png"
Content-Type: image/png


------WebKitFormBoundaryEDgRU4CNKJQjnIA8
Content-Disposition: form-data; name="media"; filename="Skärmavbild 2017-10-29 kl. 12.16.50.png"
Content-Type: image/png


------WebKitFormBoundaryEDgRU4CNKJQjnIA8--

表单的提交是在页面特定对象home中进行的:

const home = {
    'el': {
        'inputs': {
            'form': document.querySelector('form'),
            'input': document.querySelector('input')
        }
    },
    'init': function(){
        home.setupForm();
    },
    'setupForm': function(){
        home.el.inputs.input.addEventListener('change', home.upload);
    },
    'upload': function(){
        const uploader = new Uploader(home.el.inputs.form);
        uploader.upload(res => {
            console.log(res);
        });
    }
}

home.init();

...表单本身很简单:

<form method="POST" action="#">
    <input type="file" name="media">
</form>

【问题讨论】:

  • 嗯,很奇怪。它一直在发生,起初我认为这是特定于浏览器的问题,但它发生在 Chrome 和 Safari 中。
  • @Andreas 在我看来,即使在您的 plunker 中也确实会发生这种情况。查看发送的请求时,即使在那里也添加了两个文件。
  • 对不起,我以为你在谈论两个请求... :|
  • new FormData(this._form); 这将创建一个新的 FormData 对象,其中包含传递表单的所有输入元素。之后,您手动添加所有输入字段 -> 1 + 1 = 2
  • 啊,所以它在初始化FormData实例时已经从表单中添加了字段?

标签: javascript ajax file-upload


【解决方案1】:

创建 FormData 实例会自动附加所提供表单的字段。因此,在发送请求之前,所有文件都被添加了两次。

【讨论】:

    猜你喜欢
    • 2017-12-06
    • 1970-01-01
    • 2011-05-14
    • 1970-01-01
    • 2012-03-12
    • 2015-09-15
    • 1970-01-01
    相关资源
    最近更新 更多