Firebase存储:字符串与格式base64:无效的字符不匹配.仅在调试关闭时 [英] Firebase Storage: string does not match format base64: invalid character found. Only when debug is off

查看:79
本文介绍了Firebase存储:字符串与格式base64:无效的字符不匹配.仅在调试关闭时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将图像文件上传到Firebase存储,保存下载URL,并在上传完成后加载它.当我远程运行带有调试js的应用程序时,它运行良好.当我关闭调试模式时,它将停止使用无效格式异常.当我在真实设备(iOS和Android)上运行时,也会发生同样的情况

I'm trying to upload an image file to firebase storage, save the download URL, and load it after the upload is completed. When I run the app with debug js remotely on it works fine. 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)

React Native Image Picker的base64响应数据似乎是正确的

The base64 response data from React Native Image Picker seems to be correct

这是我的代码

...
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?

谢谢.

推荐答案

经过研究和调试,我找到了问题的原因和解决方案.

After some research and debug I found the cause of the issue and a solution for it.

Firebase使用 atob 方法解码由putstring方法发送的base64字符串. 但是,由于JavaScriptCore不默认支持atobbtoa,因此无法转换base64字符串,因此

Firebase uses atob method to decode the base64 string sent by putstring method. 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.

当我们在远程调试javascript模式下运行该应用程序时,所有javascript代码都在支持atobbtoa的chrome环境下运行.这就是为什么代码在调试打开时起作用而在调试关闭时不起作用的原因.

When we run the app in debug javascript remotely mode, all javascript code is run under chrome environment, where atob and btoa are supported. That's why the code works when debug is on and doesn't when its off.

要在React Native中处理atobbtoa,我们应该编写我们自己的encoding/decode方法,或者安装一个lib来为我们处理.

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.

就我而言,我更喜欢安装 base-64 lib

In my case I preferred to install 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;

用法:

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

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

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

选择使用自定义脚本或lib之后,现在我们必须将以下代码添加到index.js文件中:

After choosing either to use the custom script or the lib, now we must add the following code to the index.js file:

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

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

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

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

这将全局声明atobbtoa.因此,每当在应用程序中调用这些函数时,React Native都会使用全局范围来处理它,然后从base-64 lib触发encodedecode方法.

This will declare atob and btoa globally. 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.

这是Base64问题的解决方案.

So this is the solution for Base64 issue.

但是,解决此问题后,尝试上传较大的图像时发现了另一个问题Firebase Storage: Max retry time for operation exceed. Please try again.似乎firebase对React Native的支持上有一些限制上传,如此问题所示

However, after this is solved, I found another issue Firebase Storage: Max retry time for operation exceed. Please try again when trying to upload larger images. It seems that firebase has some limitation on support to React Native uploads, as this issue suggests.

我相信react-native-firebase可能不会为此感到挣扎,因为它已经准备好在本机上运行,​​而不是像firebase那样使用Web环境.我尚未测试它以确认,但是看来这将是处理它的最佳方法.

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. 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.

这篇关于Firebase存储:字符串与格式base64:无效的字符不匹配.仅在调试关闭时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆