EDIT:对于访问此问题的任何人,请阅读onRequest和onCall函数之间的区别.了解如何在客户端代码中调用它们.了解这里的问题应该会有所帮助.

我正在用firebase为后端构建一个个人项目,并为前端做出react .我正在try 从云函数中正确返回错误.客户端显示的错误不是从服务器发送的错误.我将在下面演示这个问题.

我希望客户端显示一个错误,显示"邮箱地址已被其他帐户使用".从下面的屏幕截图中可以看到,这就是作为响应对象发送的内容.然而,每当我做控制台时.日志(log)(err.message)在客户端显示"无效参数".(请参见下面屏幕截图中的控制台日志(log)).

Request information

这是代码.

Cloud functions - index.ts

export const registerUser = https.onRequest((req, resp) => {
cors(req, resp, async () => {
    const data = req.body.data;
    const userData: IUserData = {
      firstName: data.firstName,
      lastName: data.lastName,
      statusId: 1,
      customerId: ''
    }
    
    try {
      // Create auth user in firebase
      const newAuthUser = await admin.auth().createUser({
        email: data.email,
        emailVerified: false,
        password: data.password,
        displayName: data.firstName + ' ' + data.lastName,
        disabled: false
      })
      // Create a stripe customer
      const uid = newAuthUser.uid;
      const stripeCustomer = await createStripeCustomer(data, uid);
      userData.customerId = stripeCustomer.id;
      // Create user doc in firestore
      const storeUserRef = app.firestore().doc('/users/' + uid);
      const storeUser = await storeUserRef.set(userData);
      resp.status(200).json({
        user: storeUser,
        message: "User successfully registered"
      }).send();
      return;
    } catch (err: any) {
      console.log(err);
      resp.status(400).send(err);
      return;
    }
  })
})

React - SignupPage.tsx

function SignUpPage() {
  const firebaseAuth = getAuth(FIREBASE_APP);
  const functions = getFunctions(FIREBASE_APP);
  const [auth, loading] = useAuthState(firebaseAuth);
  const [regError, setRegError] = useState("")
  const nav = useNavigate();
  const { register, handleSubmit, formState: { errors }, } = useForm();
  const [registering, setRegistering] = useState(false);
  const registerUser = httpsCallable(functions, 'registerUser');
  connectFunctionsEmulator(functions, "localhost", 5001);
  
  // Check if a user login exists
  useEffect(() => {
    // If the auth has finished loading and the user exists, redirect to the
    // user account page
    if (auth && !loading) { nav('/account') }
  }, [auth, loading, nav])

  /**
   * Form on submit
   * @param data 
   */
  const onSubmit = (data: any) => {
    setRegistering(true);
    setRegError("");
    const userData: IRegisterPayload = {
      firstName: data.firstName,
      lastName: data.lastName,
      email: data.email,
      password: data.password
    }
    registerUser(userData).then(async(res) => {
      // return await signInWithEmailAndPassword(
      //   firebaseAuth, userData.email, userData.password
      // );
      console.log('REGISTER USER SUCCESS: ', res)
    })
    .then(res => {
      console.log(res);
      nav("/account");
    })
    .catch((err) => {
      console.log('Console log err.message:', err.message);
      setRegError(err.message);
    }).finally(() => {
      setRegistering(false);
    })
  };

  return(
    <SiteLayout>
      <div className="px-3 py-5 mx-auto signup-wrapper w-100 container d-flex flex-column flex-grow-1">
        <div className="row">
          <div className="col-12 col-lg-6 col-xl-5 pe-lg-5">
            <h2 className="h2 mb-4 text-center">Sign up</h2>
            <p className="text-center">Already a member? <NavLink to={`/login`}>Login</NavLink></p>
            <form onSubmit={handleSubmit(onSubmit)}
              className="mb-2"
            >
              <div className="mb-3">
                <label>First Name</label>
                <input type={`text`}
                  className={`form-control${errors.firstName ? ' is-invalid': ''}`}
                  placeholder="Enter your first name"
                  disabled={registering}
                  {...register('firstName', { required: true})}
                />
                {errors.firstName && <small className="text-danger d-block mt-1">First Name is required</small>}
              </div>
              <div className="mb-3">
                <label>Last Name</label>
                <input type={`text`} 
                  className={`form-control${errors.lastName ? ' is-invalid': ''}`}
                  placeholder="Enter your last name"
                  disabled={registering}
                  {...register('lastName', { required: true})}
                />
                {errors.lastName && <small className="text-danger d-block mt-1">Last Name is required</small>}
              </div>
              <div className="mb-3">
                <label>Email</label>
                <input type={`email`} 
                  className={`form-control${errors.email ? ' is-invalid': ''}`}
                  placeholder="Enter your email address"
                  disabled={registering}
                  {...register('email', { required: true})}
                />
                {errors.email && <small className="text-danger d-block mt-1">Email is required</small>}
              </div>
              <div className="mb-4">
                <label>Password</label>
                <input type={`password`} 
                  className={`form-control${errors.password ? ' is-invalid': ''}`}
                  placeholder="Enter your password"
                  disabled={registering}
                  {...register('password',{ 
                    required: "You must specify a password",
                    validate: (val: string) => {
                      // Check the entered value meets the regex requirement
                      const isStrong = PASSWORD_REGEX.test(val);
                      return (val && isStrong) || "Password does not meet criteria";
                    }
                  })}
                />
                {errors.password && <p className="small text-danger d-block my-1">{errors.password.message}</p>}
                <small className="text-muted">Passwords must be a minimum of 8 characters and include:</small>
                <ul className="small text-muted">
                  <li>At least 1 uppercase letter</li>
                  <li>At least 1 lowercase letter</li>
                  <li>At least 1 special character</li>
                  <li>At least 1 number</li>
                </ul>
              </div>
              <Button isLoading={registering}
                isSubmit={true}
                loadingLabel="Registering..."
                className="w-100"
              >
                Sign up
              </Button>
              {regError &&
                <Message severity="error" text={regError} className="my-3 w-100" />
              }
            </form>
            <p className="small text-muted">
            By signing up, you confirm that you accept the Terms of Service and Privacy Policy. This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.
            </p>            
          </div>
        </div>
      </div>
    </SiteLayout>
  );
}
export default SignUpPage;

有人能告诉我如何显示我想要的错误消息吗?

推荐答案

在你的客户端应用程序中,你说regusterUser是一个"可调用"类型的函数,但它并没有以这种方式部署在你的后端.

// here you are saying that the backend is a "callable" type function
const registerUser = httpsCallable(functions, 'registerUser');

但是,您的后端使用的是普通的HTTP onRequest类型函数.

// here are you deploying a normal HTTP function (not "callable")
export const registerUser = https.onRequest((req, resp) => {

这行不通-不能将HTTP类型函数作为可调用函数调用.

如果希望在后端使用可调用类型函数,请按照文档中的说明使用onCall类型函数.从该链接文档中,请注意:

重要的是要记住,HTTPS可调用函数与HTTP函数相似,但只有not identical个.要使用HTTPS可调用函数,必须将平台的客户端SDK与函数一起使用.https后端API(或实现协议).

Javascript相关问答推荐

创建私有JS出口

提交表格后保留Web表格中的收件箱值?

使用下表中所示的值初始化一个二维数组

将2D数组转换为图形

WebRTC关闭navigator. getUserMedia正确

在观察框架中搜索CSV数据

如何根据当前打开的BottomTab Screeb动态加载React组件?

如何在文本字段中输入变量?

ChartJs未呈现

如何发送从REST Api收到的PNG数据响应

从Nextjs中的 Select 项收集值,但当单击以处理时,未发生任何情况

创建以键值对为有效负载的Redux Reducer时,基于键的类型检测

如何在 Select 文本时停止Click事件?

自定义确认组件未在vue.js的v菜单内打开

MongoDB受困于太多的数据

无法重定向到Next.js中的动态URL

无法使用npm install安装react-dom、react和next

对不同目录中的Angular material 表列进行排序

更新文本区域行号

使用Java脚本替换字符串中的小文本格式hashtag