Как я могу POST или PUT необработанный двоичный файл, используя React Native

Мне нужно поместить файл изображения из собственного приложения реакции на предварительно настроенный URL-адрес загрузки s3. Я видел пример с выборкой, которая загружает изображение как двоичный файл через путь, но делает это как загрузка формы, состоящей из нескольких частей. Поскольку URL-адрес загрузки s3 может воспринимать его только как необработанный двоичный файл в теле, а не как многокомпонентный тип содержимого, каков синтаксис для размещения необработанного двоичного изображения в качестве тела с использованием fetch или любой другой библиотеки в реакции родной ?

Следующий код загружает его как данные формы, а это не то, что я хочу делать.

          var photo = {
            uri: response.uri,
            name: fileName,
          };
          const body = new FormData();  // how can I do this not as a form?
          body.append('photo', photo);
          const results = await fetch('https://somes3uploadurl.com, {
            method: 'PUT',
            body,
          });

person MonkeyBonkey    schedule 23.03.2017    source источник
comment
Если stackoverflow.com/questions/36067767/ отличается от того, что вам нужно сделать, чем он отличается? (Я имею в виду кроме PUT и POST.)   -  person sideshowbarker    schedule 23.03.2017
comment
FileReader также доступен в React Native? если да, то я просто обновляю программу чтения файлов и как-то ищу событие on?   -  person MonkeyBonkey    schedule 23.03.2017
comment
@MonkeyBonkey ты нашел решение?   -  person Abdellah Alaoui    schedule 30.10.2017
comment
В итоге я просто использовал uploadcare, поэтому у меня не было возможности покопаться в этом больше.   -  person MonkeyBonkey    schedule 31.10.2017
comment
Согласно этой проблеме, FileReader на данный момент не реализован в RN; github.com/facebook/react-native/issues/21209   -  person febeling    schedule 03.04.2019


Ответы (3)


Оказывается, вы можете отправить файл несколькими способами, включая base64 и как Buffer.

Использование react-native-fs и буфер:

Загрузка в формате base64 работала, но изображение каким-то образом было повреждено. Итак, я загрузил с помощью буфера:

export const uploadToAws = async (signedRequest, file) => {
  const base64 = await fs.readFile(file.uri, 'base64')
  const buffer = Buffer.from(base64, 'base64')
  return fetch(signedRequest, {
    method: 'PUT',
    headers: {
    'Content-Type': 'image/jpeg; charset=utf-8',
    'x-amz-acl': 'public-read',
   },
    body: buffer,
  })
}

Обратите внимание, что на сервере вам нужно убедиться, что вы устанавливаете правильный Content-Type: { ContentType: "image/jpeg; charset=utf-8", 'x-amz-acl': 'public-read' }, поскольку кажется, что fetch добавляет кодировку в Content-Type.

person Abdellah Alaoui    schedule 04.11.2017
comment
Это сработало! Большое спасибо! Дело в том, что нам нужно использовать Buffer, чтобы предотвратить повреждение изображения! - person danhnn.uit; 28.11.2017
comment
Рад, что смог помочь - person Abdellah Alaoui; 01.05.2020

Вы также можете использовать следующее решение:

  /**
   * @param {{contentType: string, uploadUrl: string}} resourceData for upload your image
   * @param {string} file path to file in filesystem 
   * @returns {boolean} true if data uploaded
   */
  async uploadImage(resourceData, file) {
    return new Promise((resolver, rejecter) => {
      const xhr = new XMLHttpRequest();

      xhr.onload = () => {
        if (xhr.status < 400) {
          resolver(true)
        } else {
          const error = new Error(xhr.response);
          rejecter(error)
        }
      };
      xhr.onerror = (error) => {
        rejecter(error)
      };

      xhr.open('PUT', resourceData.uploadUrl);
      xhr.setRequestHeader('Content-Type', resourceData.contentType);
      xhr.send({ uri: file });
    })
  }

И вызовите эту функцию из своего кода, например:

  let isSuccess = await uploadImage({
    contentType: "image/jpeg",
    uploadUrl: "http://my.super.web.amazon.service..."
  }, "file:///path-to-file-in-filesystem.jpeg")

Источник: https://github.com/react-native-community/react-native-image-picker/issues/61#issuecomment-297865475

person whalemare    schedule 26.04.2019
comment
Это определенно должен быть новый принятый ответ. Чтение файла в base64 и публикация могут быть очень тяжелыми для использования памяти. Этот метод не вызывает такой проблемы, так как он считывается напрямую из файловой системы. - person Daniel Abdelsamed; 20.07.2019

Вам не нужно использовать react-native-fs или эту буферную библиотеку. Вместо этого просто прочитайте файл, используя https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsArrayBuffer и передать результат в параметр body для выборки. readAsBinaryString и readAsDataUrl дали мне странные результаты.

Примечание. Мне не нужно было добавлять ; charset=utf-8 либо в мой заголовок типа контента.

Пример:

const fileReader = new FileReader();
fileReader.addEventListener('load', (event: any) => {
  const buffer = event.target.result;
  return fetch(link.url, {
    method: 'PUT',
    body: buffer,
  })
    .then((response) => {
      if (!response.ok) {
        throw new Error(
          `${response.status}: ${response.statusText}`
        );
      }
      return response;
    })
    .then(resolve, reject);
});
fileReader.addEventListener('error', reject);
fileReader.addEventListener('abort', reject);
fileReader.readAsArrayBuffer(file);
person Glitches    schedule 27.02.2018
comment
Какой параметр нужно указать для readAsArrayBuffer? У меня есть изображение, выбранное с помощью react-native-image-picker, и все, что у меня есть, это uri файла (начиная с content://) и путь к файлу - person nicecatch; 05.04.2018
comment
Хочешь показать пример? Проблема здесь предполагает, что этот API еще не установлен; github.com/facebook/react-native/issues/21209 - person febeling; 03.04.2019