如何使用 React Native POST 或 PUT 原始二进制文件

Posted

技术标签:

【中文标题】如何使用 React Native POST 或 PUT 原始二进制文件【英文标题】:How can I POST or PUT raw binary using react native 【发布时间】:2017-08-15 21:49:36 【问题描述】:

我需要将来自 react 本机应用程序的图像文件放入预配置的 s3 上传 URL。我看到了一个 fetch 示例,它通过路径将图像作为二进制文件上传,但它是作为多部分表单上传的。因为 s3 上传 url 只能将其作为正文中的原始二进制文件 - 而不是作为多部分的内容类型,所以使用 fetch 或任何其他库在 react native 中将原始二进制图像作为正文的语法是什么?

以下代码将其作为表单数据上传 - 这不是我想要做的。

          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,
          );

【问题讨论】:

如果***.com/questions/36067767/… 与您需要做的不同,它有何不同? (我的意思是 PUT 与 POST 不同。) FileReader 是否也可用于本机反应?如果是这样,我是否只是新建一个文件阅读器并以某种方式查找 on 事件? @MonkeyBonkey 你找到解决方案了吗? 我最终只使用了uploadcare,所以没有机会深入研究。 根据this issue,目前RN中还没有实现FileReader; github.com/facebook/react-native/issues/21209 【参考方案1】:

事实证明,您可以通过多种方式发送文件,包括base64Buffer

使用react-native-fs 和buffer:

使用 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。

【讨论】:

成功了!非常感谢!问题是我们需要使用 Buffer 来防止图像损坏! 很高兴我能帮上忙【参考方案2】:

您也可以使用下一个解决方案:

  /**
   * @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

【讨论】:

这绝对需要成为新接受的答案。将文件读入 base64 并发布可能会占用大量内存。这种方法不会引起这样的问题,因为它是直接从文件系统中读取的。【参考方案3】:

您不需要使用 react-native-fs 或那个缓冲区库。相反,只需使用 https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsArrayBuffer 读取文件,将结果传递给 fetch 的 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);

【讨论】:

readAsArrayBuffer 应该指定什么参数?我有一个用 react-native-image-picker 选择的图像,我只有一个文件 uri(以 content:// 开头)和一个文件路径 想展示一个例子吗?这里的问题表明这个 API 还没有到位; github.com/facebook/react-native/issues/21209

以上是关于如何使用 React Native POST 或 PUT 原始二进制文件的主要内容,如果未能解决你的问题,请参考以下文章

如何在 React Native 中向 API 发出 POST 请求?

axios.post 返回 400 React Native 的错误请求

如何创建 POST 请求以从本地路径将文件存储在服务器上 - React Native

如何在 fetch 中传递 POST 参数以在 React Native 中将图像上传到服务器?

如何在 React Native 中构造 POST 请求正文而不是字符串化的 json 而是 json?

使用 axios 在 react-native 中使用 POST 方法获取 API 数据