firebase cloud函数在request上使用不正确返回错误的cors
编辑:对于任何访问此问题的人,请阅读OnRequest和OnCall功能之间的区别。了解如何在客户端代码中调用它们中的每一个。它应该有助于了解这里的问题。
我正在使用Firebase进行后端建立一个个人项目,并为前端做出反应。我正在尝试从云功能正确返回错误。客户端显示的错误不是从服务器发送的错误。我将证明以下问题。
我希望客户端显示一个错误,上面写着“另一个帐户已经在使用电子邮件地址”。从下面的屏幕截图中可以看到,这就是作为响应对象发送的内容。但是,每当我在客户端执行console.log(err.message)时,就会说“无效的argument”。 (请参阅下面的屏幕截图中的控制台日志)。
这是代码。
云功能 - 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;
有人可以告诉我如何显示我想要的错误消息吗?
EDIT: For anyone visiting this issue - read up on the difference between onRequest, and onCall functions. Understand how to call each of them in your client side code. It should help to understand what the problem was here.
I am building a personal project with firebase for the backend, and React for the frontend. I am trying to return errors correctly from cloud functions. The error shown by the client side isn't what is sent from the server. I will demonstrate the issue below.
I want the client side to display an error that says "The email address is already in use by another account". As you can see from the screenshot below, that is what is sent as the response object. However, whenever I do a console.log(err.message) in the client side, it says "invalid-argument". (See the console log in the screenshot below).
This is the code.
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;
Can someone please tell me how to display the error message that I want?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在您的客户端应用程序中,您说的是,regusteruser是“可呼叫”类型函数,但它并未在您的后端部署。
但是,您的后端是使用普通的http onRequest 类型功能。
这将行不通 - 您无法将HTTP类型函数称为可可。
如果您想要后端中的可呼叫类型功能,请按照文档中的说明使用 /a>类型功能。从该链接的文档中,请注意:
In your client app, you are saying that regusterUser is a "callable" type function, but it is not deployed that way in your backend.
However, your backend is using an normal HTTP onRequest type function instead.
This won't work - you can't call HTTP type functions as a callable.
If you want a callable type function in your backend, follow the instructions in the documentation to use an onCall type function instead. From that linked documentation, note: