使用Fetch和FormData APIs上传多个文件

18

我正在尝试使用原生的FetchFormData API一次性上传多个文件到服务器,但是我无论如何都无法让它工作。以下是我的代码:

// acceptedFiles are File objects coming from `react-dropzone`.
function handleSubmit(acceptedFiles) {
  const data = new FormData();

  for (const file of acceptedFiles) {
    data.append('files', file, file.name);
  }

  return fetch('https://example.com/api/upload', {
    method: 'POST',
    body: data,      
  });
}

但是我的Rails服务器接收到的是这样的内容:
Parameters: {"files"=>#
<ActionDispatch::Http::UploadedFile:0x00007feb347becc0 @tempfile=#
<Tempfile:/var/folders/kl/y1jrp7zs55sbx075jjjl3p280000gn/T/RackMultipart201
71112-6486-1ftkufy.mp4>, @original_filename="SampleVideo_1280x720_5mb.mp4",
 @content_type="video/mp4", @headers="Content-Disposition: form-data; 
name=\"files\"; filename=\"SampleVideo_1280x720_5mb.mp4\"\r\nContent-Type:
 video/mp4\r\n">}

换句话说,看起来files实际上只是一个文件。但是关于FormData的文档表示,append应该添加多个文件
那么问题出在哪里?

这可能是相关的:https://github.com/rack/rack/issues/566 - Maros
3个回答

35

解决方案是将files更改为files[]

// acceptedFiles are File objects coming from `react-dropzone`.
function handleSubmit(acceptedFiles) {
  const data = new FormData();

  for (const file of acceptedFiles) {
    data.append('files[]', file, file.name);
  }

  return fetch('https://example.com/api/upload', {
    method: 'POST',
    body: data,      
  });
}

1
无法相信有这么多的例子,却没有人使用 []。 - KD.S.T.

0
// acceptedFiles are File objects coming from `react-dropzone`.
function handleSubmit(acceptedFiles) {
  const data = new FormData();

  for (const [index, file] of acceptedFiles) {
    data.append('files' + index, file, file.name);
  }

  return fetch('https://example.com/api/upload', {
    method: 'POST',
    body: data,      enter code here
  });
}

1
您的答案可以通过添加更多支持信息进行改进。请[编辑]以添加更多详细信息,例如引文或文档,以便他人可以确认您的答案是否正确。您可以在帮助中心找到有关如何撰写良好答案的更多信息。 - Ethan

0

关于发送多个文件,我做了一点不同的处理,因为我的 PHP API 端点在我使用 formdata.append('files[]', file) 发送时只会显示一个文件。

<input type="file" multiple data-sender="{{ user.hashIdentifier }}">

/** @type {HTMLInputElement} */
const input = document.querySelector('input[type=file]');
input.addEventListener('input', function listener(event){

  if(input.files.length > 0){
    const formData = new FormData();

    for(let i = 0; i < input.files.lenght; i++){
      formData.append(`file_${i}`, input.files[i]);
    }

    // my endpoint should know who sends the file

    formData.append('identify', input.dataSet.sender);

    sendData(formData);

  } else {
    console.error('no files selected');
  }   
});

/** 
 * sending the formData Object with all files to the server
 * @param {FormData} formData 
 */
function sendData(formData) {
  const url = '/api/saveFiles';
  const options = {
    method: 'POST',
    body: formData
  };

  fetch(url, options)
    .fetch((response) => {
      if(!response.ok) {
        throw Error(response.statusText);
      }

      return response.json();
    })
    .fetch((data) => {
      console.log('success', data);
    })
    .catch((error) => {
      console.error(error);
    })

}

我的 PHP 是一个 Symfony 项目,看起来像这样:


/**
 * @param Request $request (inject symfonys http request)
 * @param FileService $fileService (inject my own FileService)
 * @returns Response (symfony http Response)
 */
#[Route('/api/saveFiles', name: 'api_saveFiles', methods: ['POST'])]
public function api_saveFiles(Request $request, FileService $fileService): Response
{
  $statusCode = 409; // Conflict

  $result = array();
  
  /** @var FileBag */
  $fileBag = $request->files;

  if($fileBag->count() > 0) {
    $statusCode=200;
    $result['numberOfFiles'] = $fileBag->count();
    $result['keys'] = $fileBag->keys();

    $result['infos'] = array();
    foreach($fileBag->keys() as $key){
      try {
        $file = $fileBag->get($key);
        $fileInfo = $fileService->saveFile($file); // saves the file and gives back some infos
        $result['infos'][$fileInfo];
      } catch(Exception $ex) {
        // TODO: handle errors
      }    

    }
  }

  return new JsonResponse($result, $statusCode);
}


在尝试中,我使用了formData.append('files[]', file);,但PHP只捕获了最后一个文件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接