无法在客户端附加带有多个压缩图像的 FormData() 对象

Posted

技术标签:

【中文标题】无法在客户端附加带有多个压缩图像的 FormData() 对象【英文标题】:Can't append FormData() object with multiple compressed images on the client side 【发布时间】:2021-07-23 02:55:39 【问题描述】:

我正在尝试在发出请求之前使用Compressor JS 在客户端压缩图像,因为以原始大小上传它们需要很多时间。 我遇到的问题: 我的代码中有一个 FormData() 对象声明为“fd”,当我尝试通过 Compressor JS 中的成功钩子函数向它附加图像时,它什么也没做(对象保持原样)。 这里是代码

var fd = new FormData();
const fileList = document.querySelector('[type=file]').files;

for (file of fileList) 
                
    new Compressor(file, 
        quality: 0.4,
        maxWidth: 800,
        success: function (result) 
            fd.append('compressedImage', result, result.name);
        ,
    );

基本上,我正在遍历文件数组并逐个压缩每个图像。 我注意到了什么: 通过在循环之前创建一个新的空数组并将每个图像附加到它应该给我一个数组中的所有压缩图像。 这就是我的意思

const fileList = document.querySelector('[type=file]').files;

compressedImgs = [];

for (file of fileList) 

    new Compressor(file, 
        quality: 0.4,
        maxWidth: 800,
        success: function (result) 
            compressedImgs.push(result);
        ,
    );

然而console.log(compressedImgs) 输出这个(没什么异常,因为我在输入中添加了 2 张图像): Click here to see the output 但是当我尝试记录数组的一个元素(例如compressedImages [0])时,输出undefined。 我需要一种方法将我的压缩文件放入 FormData() 以便能够将它们发送到服务器。

【问题讨论】:

【参考方案1】:

在我传递给您的 wetransfer 链接中,有一个使用 CompressorJS 库并保存在 php 中的完整示例。它正在工作,如果您忽略了某些东西,它可能会帮助您解决问题。

此外,如果它有帮助并且您可以解决问题,那么如果您评论一下您是如何解决它的,将会很有帮助。

下面是我正常工作的代码:

index.html

<input type="file" accept="image/*" multiple>
<script>

    const formData = new FormData()

    window.addEventListener('load', function () 

        const fileInput = document.querySelector('[type=file]')

        fileInput.addEventListener('change', function (e) 

            const files = e.target.files
            const promises = []

            for (let file of files) 

                promises.push(new Promise(function (resolve, reject) 
                    new Compressor(file, 
                        quality: 0.6,
                        success(result) 
                            formData.append('files[]', result, result.name)
                            console.log(result)
                            resolve()
                        ,
                        error(err) 
                            console.log(err.message)
                            reject()
                        ,
                    )
                ))

            

            Promise.all(promises).then(function () 
                console.log(Array.from(formData.values()))
                const request = new XMLHttpRequest()
                request.open("POST", "./files-handler.php")
                request.send(formData)
            )

        )

    )

</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/compressorjs/1.0.7/compressor.min.js"></script>

files-handler.php

$data = [];

$data['_FILES'] = $_FILES;
$data['_POST'] = $_POST;
$data['uploadedFiles'] = [];

$uploadDir = __DIR__ . '/uploads/';

$data['uploadDir'] = $uploadDir;

if (!file_exists($uploadDir)) 
    mkdir($uploadDir, 0777);


$filesInput = $_FILES['files'];
$filesName = $filesInput['name'];
$filesTmpName = $filesInput['tmp_name'];
$filesError = $filesInput['error'];

foreach ($filesName as $index => $name) 

    if ($filesError[$index] == \UPLOAD_ERR_OK) 
        $toPath = $uploadDir . uniqid() . '_' . $name;
        $uploaded = move_uploaded_file($filesTmpName[$index], $toPath);
        if ($uploaded) 
            $data['uploadedFiles'][] = $toPath;
        
    



header('Content-Type: application/json');

echo json_encode($data);

【讨论】:

就是这样!它解决了这个问题。实际问题可能是因为我没有承诺,并且表单数据对象被发送到服务器而没有压缩器完成其工作,因为它是一个异步过程 我认为第一个答案还不够,我很高兴它解决了您的问题。问候。【参考方案2】:

尝试将compressedImage 更改为compressedImage[]

类似:

let formData = new FormData()
let fileInput = document.querySelector('[type=file]')

fileInput.addEventListener('change', function(e)
    
    let files = e.target.files
    
    for(let file of files)
        formData.append('files[]', file)
    
    
    console.log(Array.from(formData.values()))
    
)
&lt;input type="file" multiple/&gt;

编辑 1: 查看表单提交代码以及一些服务器代码会很有用。

但是,我想到另一件事是您使用Content-Type multipart/form-data 提交文件吗?

以上对于向服务器提交文件很重要。

【讨论】:

我应用了您建议的更改,但 formData 仍然没有附加,我认为这是因为压缩后文件被转换为 blob,但我尝试再次将其设为文件,但仍然没有结果.顺便说一句,在服务器端它会显示一个警告,即没有这样的索引。 有一个在 PHP 中发送和保存的工作示例:wetransfer.com/downloads/… 是的,内容类型是 multipart/formdata,但我的想法是我什至不能将文件放在一个简单的数组中,如果我尝试按索引记录它们,它们也不会出现在那里,但是记录整个数组确实可以正确显示它们,只需仔细查看我在问题中提出的示例,这很奇怪

以上是关于无法在客户端附加带有多个压缩图像的 FormData() 对象的主要内容,如果未能解决你的问题,请参考以下文章

React Native:无法在“FormData”上执行“附加”:参数 2 不是“Blob”类型。在新的 ApolloError

我想提交一个包含多个图像文件的反应式表单

如何将np数组转换为StringIO

如何在不使用 Java 的情况下压缩 .csv 文件并在电子邮件中附加 Oracle plsql

将 GestureRecogniser 附加到多个图像视图

是否可以绘制带有箭头的图形,如 MATLAB 中附加的图像所示?