Meteor调用createUser触发EJSON.clone循环引用错误求助
嘿,我帮你梳理下这个问题——你遇到的EJSON.clone循环调用错误,大概率和代码里的几个不合理操作以及Meteor用户对象的规范有关,咱们一步步来解决:
1. 先删掉多余的手动登录逻辑
首先要明确:Meteor的Accounts.createUser在成功创建用户后,会自动帮你完成登录,完全不需要再手动调用Meteor.loginWithPassword。这一步多余的调用不仅没必要,还可能触发内部状态的冲突,间接导致EJSON序列化时出问题。
把这段冗余代码删掉:
// 删掉这段多余的登录逻辑 Meteor.loginWithPassword(email, password, function(err) { if (err) { console.log("Error logging in"); console.log(err); Materialize.Toast.removeAll(); Materialize.toast("There was an error logging you in. Try logging in manually. If this error persists, contact support.", 8000); } else { console.log("Logged in!"); FlowRouter.go('/'); } })
改成直接在createUser成功回调里跳转:
Accounts.createUser(accountInfo, function(err) { if (err) { // ...你的错误处理逻辑 } else { console.log("用户创建成功,已自动登录!"); FlowRouter.go('/'); } });
2. 修复变量未定义的坑
顺便提一句,你原来的Meteor.loginWithPassword(email, password)里的email和password是未定义的变量——你应该用accountInfo.email和accountInfo.password。不过既然我们已经删掉了这段代码,这个问题也就顺带解决了。
3. 调整服务端用户对象的结构,符合Meteor规范
你在服务端onCreateUser里直接把options.email赋值给user.email,但Meteor默认的用户结构中,邮箱是存在user.emails数组里的(每个元素包含address和verified字段)。额外添加的user.email字段可能干扰Meteor内部的序列化逻辑,这很可能是EJSON循环调用的根源。
修改服务端代码,遵循Meteor的默认结构:
import { Meteor } from 'meteor/meteor'; import { Accounts } from 'meteor/accounts-base'; Accounts.onCreateUser((options, user) => { // 保留默认的profile处理逻辑 if (options.profile) { user.profile = options.profile; } // 自定义字段直接作为user的顶层字段没问题 user.first_name = options.first_name; user.last_name = options.last_name; user.phone_number = options.phone_number; // 邮箱交给Meteor自动处理即可,createUser会自动把options.email加入user.emails数组 return user; });
4. 排查EJSON循环引用的其他可能
如果上面的调整后还是有问题,那你需要检查:
accountInfo里的每个字段是不是都是基本类型(字符串、数字),有没有不小心传入了对象/数组或者存在循环引用的值;- 有没有第三方库(比如Materialize相关的代码)修改了全局对象,影响了EJSON的序列化逻辑;
- 尝试把Meteor的
accounts-base、ejson包更新到最新版本,可能是旧版本的bug导致的。
5. 暂时移除sleep延迟测试
虽然sleep函数本身不会导致循环引用,但建议先把它去掉,排除异步延迟带来的状态问题,先确保createUser的基础调用能正常工作。
调整后的客户端代码示例
onSubmit(e) { let input_valid = this.validateInput(); if (!input_valid) { Materialize.updateTextFields(); e.preventDefault(); return; } Materialize.Toast.removeAll(); let $toastContent = $('<div class="container" style="width: 200px"><div class="row">Creating account...</div><div class="row"><div class="progress"><div class="indeterminate"></div></div></div></div>'); Materialize.toast($toastContent, 10000); let accountInfo = { first_name: this.state.first_name.value, last_name: this.state.last_name.value, email: this.state.email.value, password: this.state.password.value, phone_number: this.state.phone_number.value, }; Accounts.createUser(accountInfo, (err) => { Materialize.Toast.removeAll(); if (err) { console.error("创建用户出错:", err); Materialize.toast("创建账户时出错,请稍后重试。如果问题持续,请联系支持人员。", 8000); } else { console.log("用户创建成功!"); FlowRouter.go('/'); } }); e.preventDefault(); }
按照上面的步骤逐一调整,应该就能解决你遇到的EJSON循环调用错误了。
内容的提问来源于stack exchange,提问作者TheWaffleDimension




