You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native无法连接Firebase Cloud Functions API求助

React Native调用Firebase Cloud Functions API返回Axios Network Error

环境与问题概述

  • 技术栈:React Native 0.73 + Node Express + Firebase Firestore(免费版)
  • 单独测试正常:API通过Postman/浏览器可正常访问,React Native应用在外部设备可运行
  • 异常情况:调用公共API(如jsonplaceholder)正常,但调用本地部署的Firebase Cloud Functions API时返回Axios Error: Network Error
  • 已尝试:关闭防火墙、修改端口,问题未解决;npx react-native run-android报错,目前用npm start运行应用;Firebase配置遵循官方文档

API代码(Firebase Cloud Functions)

const functions = require("firebase-functions");
const admin = require("firebase-admin");
const express = require("express");
const cors = require("cors");
const app = express();

const permisos = require("./permisos.json");

admin.initializeApp({
  credential: admin.credential.cert(permisos),
  databaseURL: "https://url-que-te-da-firestore.firebaseio.com",
});

const db = admin.firestore();

app.use(cors({origin: true}));

exports.app = functions.https.onRequest(app);

/**
 * Genera un objeto de respuesta con un formato específico.
 *
 * @param {string} codigo - El código de estado de la respuesta.
 * @param {any} entrada - La entrada o resultado de la operación.
 * @return {Object} Objeto de respuesta con un formato específico.
 */
function salida(codigo, entrada) {
  const today = new Date();
  const date = today.getFullYear()+"-"+
    (today.getMonth()+1)+"-"+
    today.getDate()+"|"+
    today.getHours() + ":" +
    today.getMinutes() + ":" +
    today.getSeconds();

  if (codigo === "200") {
    return {
      mensaje: "Proceso terminado exitosamente",
      folio: date,
      resultado: entrada,
    };
  }

  if (codigo === "201") {
    return {
      mensaje: "Elemento creado exitosamente",
      folio: date,
      resultado: entrada,
    };
  }

  if (codigo === "500") {
    return {
      mensaje: "Ocurrio un detalle en el servidor",
      folio: date,
      resultado: entrada,
    };
  }

  return {
    mensaje: "Ocurrio un detalle en el servidor",
    folio: date,
    resultado: entrada,
  };
}

// Añadir libros
app.post("/books", (req, res) => {
  (async () => {
    try {
      await db.collection("books").doc("/" + req.body.id + "/")
          .create({titulo: req.body.titulo});
      return res.status(200).send(salida("200", "Libro creado correctamente"));
    } catch (error) {
      console.log(error);
      return res.status(500).send(salida("500", error));
    }
  })();
});

// Leer todos los libros
app.get("/books", async (req, res) => {
  try {
    const query = db.collection("books");
    const querySnapshot = await query.get();
    const docs = querySnapshot.docs;

    const response = docs.map((doc) => ({
      id: doc.id,
      titulo: doc.data().titulo,
    }));

    return res.status(200).json(salida("200", response));
  } catch (error) {
    return res.status(500).json(salida("500", error));
  }
});

// Leer solo 1 libro por id
app.get("/books/:id", (req, res) =>{
  (async () => {
    try {
      const doc = db.collection("books").doc(req.params.id);
      const item = await doc.get();
      const response = item.data();
      return res.status(200).json(salida("200", response));
    } catch (error) {
      return res.status(500).send(salida("500", error));
    }
  })();
});

// Modificar libros
app.put("/books/:id", async (req, res) => {
  try {
    const document = db.collection("books").doc(req.params.id);

    await document.update({
      titulo: req.body.titulo,
    });

    return res.status(200).json(salida("200", "El libro ha sido actualizado"));
  } catch (error) {
    return res.status(500).json(salida("500", error));
  }
});

// Borrar libros
app.delete("/books/:id", async (req, res) => {
  try {
    const doc = db.collection("books").doc(req.params.id);
    await doc.delete();
    return res.status(200).json(salida("200", "El libros ha sido borrado"));
  } catch (error) {
    return res.status(500).send(salida("500", error));
  }
});

React Native应用代码

import React, { useEffect, useState } from 'react';
import type { FC, ReactNode } from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
} from 'react-native';
import axios from 'axios';

type SectionProps = {
  title: string;
  children?: ReactNode;
};

const Section: FC<SectionProps> = ({ children, title }) => {
  const isDarkMode = useColorScheme() === 'dark';
  return (
    <View style={styles.sectionContainer}>
      <Text
        style={[
          styles.sectionTitle,
          {
            color: isDarkMode ? 'white' : 'black',
          },
        ]}>
        {title}
      </Text>
      <Text
        style={[
          styles.sectionDescription,
          {
            color: isDarkMode ? 'light' : 'dark',
          },
        ]}>
        {children}
      </Text>
    </View>
  );
};

const App: FC = () => {
  const isDarkMode = useColorScheme() === 'dark';
  const [dataFromServer, setDataFromServer] = useState<any>(null);

  useEffect(() => {
    // Realizar solicitud HTTP al servidor Node.js al cargar la aplicación
    //http://192.168.1.38:5000/libros-brais/us-central1/app/books
    axios.get("http://192.168.1.38:5000/libros-brais/us-central1/app/books")
      .then(response => {
        setDataFromServer(response.data);
      })
      .catch(error => {
        console.error(error);
      });
  }, []);

  const backgroundStyle = {
    backgroundColor: isDarkMode ? 'darker' : 'lighter',
  };

  return (
    <SafeAreaView style={backgroundStyle}>
      <StatusBar
        barStyle={isDarkMode ? 'light-content' : 'dark-content'}
        backgroundColor={backgroundStyle.backgroundColor}
      />
      <ScrollView
        contentInsetAdjustmentBehavior="automatic"
        style={backgroundStyle}>
        {/* ... Otros componentes ... */}
        <View
          style={{
            backgroundColor: isDarkMode ? 'black' : 'white',
          }}>
          <Section title="Step One">
            Edit <Text style={styles.highlight}>App.tsx</Text> to change this
            screen and then come back to see your edits.
          </Section>
          <Section title="Data from Server">
            <Text>{dataFromServer ? JSON.stringify(dataFromServer) : 'Loading...'}</Text>
          </Section>
          {/* ... Otras secciones ... */}
        </View>
      </ScrollView>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  sectionContainer: {
    marginTop: 32,
    paddingHorizontal: 24,
  },
  sectionTitle: {
    fontSize: 24,
    fontWeight: '600',
  },
  sectionDescription: {
    marginTop: 8,
    fontSize: 18,
    fontWeight: '400',
  },
  highlight: {
    fontWeight: '700',
  },
});

export default App;

Firebase Serve运行日志

Serving from 'C:\Users\r3mus\OneDrive\Escritorio\Proyectos\prueba brais react\prueba-brais'...

i  functions: Watching "C:\Users\r3mus\OneDrive\Escritorio\Proyectos\prueba brais react\prueba-brais\functions" for Cloud Functions...
+  functions: Using node@18 from host.
Serving at port 8292

+  functions: Loaded functions definitions from source: app.
+  functions[us-central1-app]: http function initialized (http://localhost:5000/libros-brais/us-central1/app).
!  functions: The Cloud Firestore emulator is not running, so calls to Firestore will affect production.

解决方案

1. 修正API请求端口

从日志可知,Firebase Serve的实际监听端口是8292,将React Native中的请求URL改为:

axios.get("http://192.168.1.38:8292/libros-brais/us-central1/app/books")

2. 确保设备与开发机网络连通

  • 确认外部设备和开发机处于同一WiFi网络
  • 用设备浏览器直接访问上述修正后的URL,验证是否能正常获取数据,排查网络连通问题

3. 处理Android HTTP限制

Android 9及以上默认禁止HTTP明文请求,需在android/app/src/main/AndroidManifest.xml的<application>标签中添加配置:

<application
  ...
  android:usesCleartextTraffic="true">

4. 强化CORS配置

将CORS规则明确为允许React Native调试相关地址:

app.use(cors({
  origin: ['http://localhost:8081', 'exp://*', 'http://192.168.1.38:*'],
  credentials: true
}));

5. 排查Functions本地部署问题

  • 单独启动Functions服务:firebase serve --only functions,确认地址正确性
  • 查看Functions日志:firebase functions:log,检查是否有请求到达但处理出错的情况

内容的提问来源于stack exchange,提问作者r3mus99

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 12:24:54