简体   繁体   English

Firebase 存储:字符串与格式不匹配 base64:找到无效字符。 仅当调试关闭时

[英]Firebase Storage: string does not match format base64: invalid character found. Only when debug is off

I'm trying to upload an image file to firebase storage, save the download URL, and load it after the upload is completed.我正在尝试上传一个图片文件到firebase存储,保存下载URL,上传完成后再加载。 When I run the app with debug js remotely on it works fine.当我远程运行带有 debug js 的应用程序时,它工作正常。 When I turn off debug mode it stops working with the invalid format exception.当我关闭调试模式时,它会停止处理无效格式异常。 The same happens when I run in a real device (both iOS and Android)当我在真实设备(iOS 和 Android)中运行时也会发生同样的情况

The base64 response data from React Native Image Picker seems to be correct来自 React Native Image Picker 的 base64 响应数据似乎是正确的

Here's my code这是我的代码

...
import * as ImagePicker from 'react-native-image-picker'; //0.26.10
import firebase from 'firebase'; //4.9.1
...

handleImagePicker = () => {
    const { me } = this.props;
    const options = {
      title: 'Select pic',
      storageOptions: {
        skipBackup: true,
        path: 'images'
      },
      mediaType: 'photo',
      quality: 0.5,
    };
    ImagePicker.showImagePicker(options, async (response) => {
        const storageRef = firebase.storage().ref(`/profile-images/user_${me.id}.jpg`);

        const metadata = {
          contentType: 'image/jpeg',
        };

        const task = storageRef.putString(response.data, 'base64', metadata);
        return new Promise((resolve, reject) => {
          task.on(
            'state_changed',
            (snapshot) => {
              var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
              console.log('Upload is ' + progress + '% done');
            },
            (error) =>
              console.log(error),
            () => {
              this.onChangeProfileImage();
            }
          );
        });
     }
}

onChangeProfileImage = async () => {
    const { me } = this.props;

    const storageRef = firebase.storage().ref(`/profile-images/user_${me.id}.jpg`);

    const profileImageUrl = await new Promise((resolve, reject) => {
      storageRef.getDownloadURL()
      .then((url) => {
        resolve(url);
      })
      .catch((error) => {
        console.log(error);
      });
    });


  // some more logic to store profileImageUrl in the database

  }

Any idea how to solve this?知道如何解决这个问题吗?

Thanks in advance.提前致谢。

The problem is now solved using fetch() API. The promise returned can be converted to blob which you can upload to firebase/storage现在使用fetch() API 解决了问题。返回的 promise 可以转换为 blob,您可以将其上传到 firebase/storage

Here is an example这是一个例子

 let storageRef = storage().ref();
 let imageName = data.name + "image";
 let imagesRef = storageRef.child(`images/${imageName}`);

 const response = await fetch(image); 
 const blob = await response.blob(); // Here is the trick

 imagesRef
      .put(blob)
      .then((snapshot) => {
        console.log("uploaded an image.");
      })
      .catch((err) => console.log(err));

After some research and debug I found the cause of the issue and a solution for it. 经过一些研究和调试后,我找到了问题的原因并找到了解决方案。

Why does it happen? 为什么会这样?

Firebase uses atob method to decode the base64 string sent by putstring method. Firebase使用atob方法解码putstring方法发送的base64字符串。 However, since JavaScriptCore doesn't have a default support to atob and btoa , the base64 string can't be converted, so this exception is triggered. 但是,由于JavaScriptCore没有对atobbtoa的默认支持,因此无法转换base64字符串,因此会触发异常。

When we run the app in debug javascript remotely mode, all javascript code is run under chrome environment, where atob and btoa are supported. 当我们在调试javascript远程模式下运行应用程序时,所有javascript代码都在chrome环境下运行,其中支持atobbtoa That's why the code works when debug is on and doesn't when its off. 这就是为什么代码在调试打开时工作,而在关闭时不工作的原因。

How to solve? 怎么解决?

To handle atob and btoa in React Native, we should either write our own encode/decode method, or install a lib to handle it for us. 要在React Native中处理atobbtoa ,我们应该编写自己的编码/解码方法,或者安装一个lib来为我们处理它。

In my case I preferred to install base-64 lib 在我的情况下,我更喜欢安装base-64 lib

But here's an example of a encode/decode script: 但这是一个编码/解码脚本的例子:

const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const Base64 = {
  btoa: (input:string = '')  => {
    let str = input;
    let output = '';

    for (let block = 0, charCode, i = 0, map = chars;
    str.charAt(i | 0) || (map = '=', i % 1);
    output += map.charAt(63 & block >> 8 - i % 1 * 8)) {

      charCode = str.charCodeAt(i += 3/4);

      if (charCode > 0xFF) {
        throw new Error("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");
      }

      block = block << 8 | charCode;
    }

    return output;
  },

  atob: (input:string = '') => {
    let str = input.replace(/=+$/, '');
    let output = '';

    if (str.length % 4 == 1) {
      throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");
    }
    for (let bc = 0, bs = 0, buffer, i = 0;
      buffer = str.charAt(i++);

      ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
        bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
    ) {
      buffer = chars.indexOf(buffer);
    }

    return output;
  }
};

export default Base64;

Usage: 用法:

import Base64 from '[path to your script]';

const stringToEncode = 'xxxx';
Base64.btoa(scriptToEncode);

const stringToDecode = 'xxxx';
Base64.atob(stringToDecode);

After choosing either to use the custom script or the lib, now we must add the following code to the index.js file: 在选择使用自定义脚本或lib之后,现在我们必须将以下代码添加到index.js文件中:

import { decode, encode } from 'base-64';

if (!global.btoa) {
    global.btoa = encode;
}

if (!global.atob) {
    global.atob = decode;
}

AppRegistry.registerComponent(appName, () => App);

This will declare atob and btoa globally. 这将在全球宣布atobbtoa So whenever in the app those functions are called, React Native will use the global scope to handle it, and then trigger the encode and decode methods from base-64 lib. 因此,只要在应用程序中调用这些函数,React Native将使用全局范围来处理它,然后从base-64 lib触发encodedecode方法。

So this is the solution for Base64 issue. 所以这是Base64问题的解决方案。

However, after this is solved, I found another issue Firebase Storage: Max retry time for operation exceed. Please try again 但是,在此问题解决后,我发现Firebase Storage: Max retry time for operation exceed. Please try again另一个问题Firebase Storage: Max retry time for operation exceed. Please try again Firebase Storage: Max retry time for operation exceed. Please try again when trying to upload larger images. Firebase Storage: Max retry time for operation exceed. Please try again上传较大的图片时Firebase Storage: Max retry time for operation exceed. Please try again It seems that firebase has some limitation on support to React Native uploads , as this issue suggests. 正如这个问题所暗示的那样, firebase似乎对React Native上传的支持有一些限制。

I believe that react-native-firebase may not struggle on this since it's already prepared to run natively, instead of using the web environment as firebase does. 我相信react-native-firebase可能不会在这方面挣扎,因为它已经准备好本地运行,而不是像firebase一样使用web环境。 I didn't test it yet to confirm, but it looks like this will be the best approach to handle it. 我还没有测试它确认,但看起来这将是处理它的最佳方法。

Hope this can be helpful for someone else. 希望这对其他人有帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么当我将 base64 图像上传到 firebase 时,它在存储中显示扩展名为 application/octet - Why is it that when I upload a base64 image to firebase it shows in storage with extension application/octet 将图像作为 base64 字符串发送到 Firebase Cloud Functions 的效率 - Efficiency sending images as base64 string to Firebase Cloud Functions 将 base64 字符串编码图像/字节图像作为图像传递到 Firebase ML Vision Flutter 中进行处理 - Passing a base64 string encoded image/ byte image as an image for processsing in Firebase ML Vision in Flutter 在云中使用 firebase-admin 将 Base64 编码的 PDF 字符串保存到 firebase 存储 function - Saving a Base64-encoded PDF string to firebase storage using firebase-admin in a cloud function “未找到存储连接字符串。” 当试图从 azure 功能核心工具中列出持久的 function 实例时 - 'No storage connection string found.' when trying to list durable function instances from azure functions core tools 如何判断base64和unicode字符是否等价? - How to determine if base64 and unicode character are equivalent? 将二进制文件提取为 base64 字符串会导致文件不完整? - Extracting binary as base64 String results in incomplete file? 当我上传数据到firebase时,有时最后一个字符被截断 - When I upload data to firebase, sometimes the last character is cut off 如何使用 AWS Lambda [NodeJS] 将 base64 编码字符串作为图像上传到 S3 - How to upload a base64 encoding string as an image to S3 using AWS Lambda [NodeJS] 从 base64 编码字符串解析 Azure 逻辑应用程序中的 JSON 数组,以在 For_each 中使用 - Parsing JSON array in Azure Logic App from base64 encoded string to use in For_each
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM