首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >react后台本地(世博)上传文件

react后台本地(世博)上传文件
EN

Stack Overflow用户
提问于 2022-05-26 23:40:35
回答 2查看 1K关注 0票数 4

在我的世博(反应-本地)应用程序,我想做上传任务,即使应用程序是在后台或死亡。

  • 上传应该进行到firebase存储,所以我们没有REST。
  • 查看了世博会任务经理库,但我不知道该如何做。世博是否有可能达到这个目标?TaskManager是否是此任务的正确包?
  • 只有一些世博包可以注册为一个任务(例如backgroundFetch),并且不可能注册自定义函数(在本例中是uploadFile方法)。
  • 我甚至更加困惑,因为我们应该为iOS启用add iOS键,但是它只有audio,location,voip,external-accessory,bluetooth-central,bluetooth-peripheral,fetch,remote-notification,processing作为可能的值。

如果你能至少指导我从哪里开始或者搜索什么,即使应用程序在后台被杀死/终止,我也很感激你能够上传文件。

代码语言:javascript
复制
   import { getStorage, ref, uploadBytes } from "firebase/storage";    
    const storage = getStorage();
    const storageRef = ref(storage, 'videos');    
    const uploadFile = async (file)=>{ 
      // the file is Blob object
      await uploadBytes(storageRef, file);
    }
  • 我已经复习了react-native-background-fetchreact-native-background-uploadreact-native-background-jobupload应该弹出世博,job不支持iOS,而fetch是为间隔执行任务而设计的一项令人抓取的任务。如果有办法使用上述图书馆,请指导我:)
  • 据我所知,Firebase不接受文件,对吗?如果是的话请给我举个例子。如果我可以使存储json与文件上传工作,那么我可以使用世博asyncUpload可能不会弹出。
EN

回答 2

Stack Overflow用户

发布于 2022-06-21 03:03:27

希望这不会太晚对你有帮助。最近我一直在处理各种各样的世博<->防火墙存储集成,下面是一些可能会有所帮助的信息。

首先,我建议不要使用Firebase的uploadBytes / uploadBytesResumable方法。这条线对此进行了长期的讨论,但基本上它在v9中被打破了。也许在未来,Firebase团队会解决这些问题,但是现在它与世博会的关系已经很不一样了。

相反,我建议要么沿着编写一个小型Firebase函数的路线前进,要么提供一个签名上传-url,要么处理上传本身。

--基本上,如果您可以通过http端点使存储上载工作,则可以使用任何类型的上载机制。(例如,您可能在这里寻找的FileSystem.uploadAsync()方法,如@brentvatne指出的,或者提取,或axios )。我将在最后展示一条基本线路)。

服务器端

选项1:签名的URL上传。

基本上,有一个小的firebase函数,返回一个签名的url。您的应用程序调用像/get-signed-upload-url这样的云函数,该函数返回url,然后使用该url。请查看:https://cloud.google.com/storage/docs/access-control/signed-urls,了解您将如何处理此问题。

这可能对您的用例很好。它可以像任何httpsCallable函数一样配置,因此与选项2相比,设置它的工作不多。

但是,这并不适用于firebase存储/函数模拟器!因此,我不使用这个方法,因为我喜欢集中使用模拟器,而且它们只提供所有功能的子集。

选项2:完全通过函数上传文件

这是一点干草,但给你更多的保真度超过你的上传,并将工作在一个模拟器!我也喜欢这一点,因为它允许在端点执行中执行上载过程,而不是作为副作用。

例如,您可以有一个照片上传端点生成缩略图,如果端点201的,那么您是好的!与传统的让侦听器进入云存储的方法不同的是,这种方法会产生缩略图,从而产生各种不良的竞争条件(通过指数退避检查处理完成?)真恶心!)

下面是我建议采用这种方法的三种资源:

基本上,如果您可以创建一个Firebase云端点,它可以在formdata中接受一个文件,那么可以让busboy解析它,然后您可以使用它做任何您想做的事情……就像把它上传到云存储!

这方面的概述:

代码语言:javascript
复制
import * as functions from "firebase-functions";
import * as busboy from "busboy";
import * as os from "os";
import * as path from "path";
import * as fs from "fs";

type FieldMap = {
  [fieldKey: string]: string;
};

type Upload = {
  filepath: string;
  mimeType: string;
};

type UploadMap = {
  [fileName: string]: Upload;
};

const MAX_FILE_SIZE = 2 * 1024 * 1024; // 2MB

export const uploadPhoto = functions.https.onRequest(async (req, res) => {
  verifyRequest(req); // Verify parameters, auth, etc. Better yet, use a middleware system for this like express.

  // This object will accumulate all the fields, keyed by their name
  const fields: FieldMap = {};

  // This object will accumulate all the uploaded files, keyed by their name.
  const uploads: UploadMap = {};

  // This will accumulator errors during the busboy process, allowing us to end early.
  const errors: string[] = [];

  const tmpdir = os.tmpdir();

  const fileWrites: Promise<unknown>[] = [];

  function cleanup() {
    Object.entries(uploads).forEach(([filename, { filepath }]) => {
      console.log(`unlinking: ${filename} from ${path}`);
      fs.unlinkSync(filepath);
    });
  }

  const bb = busboy({
    headers: req.headers,
    limits: {
      files: 1,
      fields: 1,
      fileSize: MAX_FILE_SIZE,
    },
  });

  bb.on("file", (name, file, info) => {
    verifyFile(name, file, info); // Verify your mimeType / filename, etc.
    file.on("limit", () => {
      console.log("too big of file!");
    });

    const { filename, mimeType } = info;
    // Note: os.tmpdir() points to an in-memory file system on GCF
    // Thus, any files in it must fit in the instance's memory.
    console.log(`Processed file ${filename}`);
    const filepath = path.join(tmpdir, filename);
    uploads[filename] = {
      filepath,
      mimeType,
    };

    const writeStream = fs.createWriteStream(filepath);
    file.pipe(writeStream);

    // File was processed by Busboy; wait for it to be written.
    // Note: GCF may not persist saved files across invocations.
    // Persistent files must be kept in other locations
    // (such as Cloud Storage buckets).
    const promise = new Promise((resolve, reject) => {
      file.on("end", () => {
        writeStream.end();
      });
      writeStream.on("finish", resolve);
      writeStream.on("error", reject);
    });
    fileWrites.push(promise);
  });

  bb.on("close", async () => {
    await Promise.all(fileWrites);

    // Fail if errors:
    if (errors.length > 0) {
      functions.logger.error("Upload failed", errors);
      res.status(400).send(errors.join());
    } else {
      try {
        const upload = Object.values(uploads)[0];

        if (!upload) {
          functions.logger.debug("No upload found");
          res.status(400).send("No file uploaded");
          return;
        }

        const { uploadId } = await processUpload(upload, userId);

        cleanup();

        res.status(201).send({
          uploadId,
        });
      } catch (error) {
        cleanup();
        functions.logger.error("Error processing file", error);
        res.status(500).send("Error processing file");
      }
    }
  });

  bb.end(req.rawBody);
});

然后,processUpload函数可以对文件做任何您想做的事情,比如将它上传到云存储:

代码语言:javascript
复制
async function processUpload({ filepath, mimeType }: Upload, userId: string) {
    const fileId = uuidv4();
    const bucket = admin.storage().bucket(); 
    await bucket.upload(filepath, {
        destination: `users/${userId}/${fileId}`,
        {
          contentType: mimeType,
        },
    });
    return { fileId };
}

移动侧

然后,在移动方面,您可以像这样与它交互:

代码语言:javascript
复制
async function uploadFile(uri: string) {

function getFunctionsUrl(): string {
  if (USE_EMULATOR) {
    const origin =
      Constants?.manifest?.debuggerHost?.split(":").shift() || "localhost";
    const functionsPort = 5001;
    const functionsHost = `http://${origin}:${functionsPort}/{PROJECT_NAME}/${PROJECT_LOCATION}`;
    return functionsHost;
  } else {
    return `https://{PROJECT_LOCATION}-{PROJECT_NAME}.cloudfunctions.net`;
  }
}


  // The url of your endpoint. Make this as smart as you want.
  const url = `${getFunctionsUrl()}/uploadPhoto`;
  await FileSystem.uploadAsync(uploadUrl, uri, {
    httpMethod: "POST",
    uploadType: FileSystem.FileSystemUploadType.MULTIPART,
    fieldName: "file", // Important! make sure this matches however you want bussboy to validate the "name" field on file.
    mimeType,
    headers: {
      "content-type": "multipart/form-data",
      Authorization: `${idToken}`,
    },
  });
});

TLDR

将云存储封装在您自己的端点中,将其视为正常的http上载,一切都很好。

票数 2
EN

Stack Overflow用户

发布于 2022-06-02 17:14:37

我已经做了类似的事情,您可以使用世博会-任务经理世博-背景-取。这是我使用的代码。我希望这对你有用。

代码语言:javascript
复制
import * as BackgroundFetch from 'expo-background-fetch';
import * as TaskManager from 'expo-task-manager';

const BACKGROUND_FETCH_TASK = 'background-fetch';
const [isRegistered, setIsRegistered] = useState(false);
const [status, setStatus] = useState(null);

//Valor para que se ejecute en IOS
BackgroundFetch.setMinimumIntervalAsync(60 * 15);

// Define the task to execute 
TaskManager.defineTask(BACKGROUND_FETCH_TASK, async () => {
  const now = Date.now();
  console.log(`Got background fetch call at date: ${new Date(now).toISOString()}`);

//   Your function or instructions you want
  return BackgroundFetch.Result.NewData;
});

// Register the task in BACKGROUND_FETCH_TASK
async function registerBackgroundFetchAsync() {
  return BackgroundFetch.registerTaskAsync(BACKGROUND_FETCH_TASK, {
    minimumInterval: 60 * 15, // 1 minutes
    stopOnTerminate: false, // android only,
    startOnBoot: true, // android only
  });
}

// Task Status 
const checkStatusAsync = async () => {
  const status = await BackgroundFetch.getStatusAsync();
  const isRegistered = await TaskManager.isTaskRegisteredAsync(
    BACKGROUND_FETCH_TASK
  );
  setStatus(status);
  setIsRegistered(isRegistered);
};

// Check if the task is already register
const toggleFetchTask = async () => {
  if (isRegistered) {
    console.log('Task ready');
  } else {
    await registerBackgroundFetchAsync();
    console.log('Task registered');
  }

  checkStatusAsync();
};

useEffect(() => {
    toggleFetchTask();
  }, []);
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72399093

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档