meteor构建app程序
This is the third of a five-part series on building a Slack clone using Meteor. The aim of these tutorials are not just for you to blindly follow instructions, but it's our hope that you'll understand the thought process and reasoning behind the architecture.
这是关于使用Meteor构建Slack克隆的五部分系列的第三部分。 这些教程的目的不仅是让您盲目遵循说明,而且我们希望您能理解架构背后的思考过程和推理。
Right now, everyone is anonymous (everyone is scotch!), and everyone talks on the same channel. Let's do something about that.
现在,每个人都是匿名的(每个人都是苏格兰人!),每个人都在同一频道上交谈。 让我们为此做些事情。
用户帐号 (User Accounts)
As with everything Meteor - there's a package for that. The accounts-base
and accounts-password
packages provide the capabilities for login, logout, account creation, email validation, password recovery. There's also the accounts-ui
and accounts-ui-unstyled
which provides you with a login / register form that you can just drop into your application.
与所有流星一样-有一个包装。 accounts-base
和accounts-password
软件包提供登录,注销,帐户创建,电子邮件验证,密码恢复的功能。 还有accounts-ui
和accounts-ui-unstyled
,它们为您提供了一个登录/注册表格,您可以将其放入应用程序中。
Using these packages, user data would be stored in the users
collection, so you must make sure your collection names do not clash with this.
使用这些软件包,用户数据将存储在users
集合中,因此您必须确保您的集合名称与此不冲突。
Let's install the packages.
让我们安装软件包。
$ meteor add accounts-base accounts-password accounts-ui
And lets drop in the login form template, provided by the accounts-ui
package, into our template.
然后,将accounts-ui
软件包提供的登录表单模板放入我们的模板中。
{{> loginButtons}}
We can see that these packages created a users
collection in our database.
我们可以看到这些软件包在我们的数据库中创建了一个users
集合。
And now let's create a dummy user.
现在让我们创建一个虚拟用户。
And now we look back into our collection, we find an entry.
现在,我们回顾我们的收藏,我们找到一个条目。
And here it is in BSON format.
这是BSON格式。
{
"_id": "e6AN2jGt9T9jrcwDt",
createdAt": ISODate("2015-05-24T15:48:21.547Z"),
"services": {
"password": {
"bcrypt": "$2a$10$6CDufWjV.OD/mQIv0MOxkukXzWgE0UZVGLAUnBF8vRHkjRKl4NoLy"
},
"resume": {
"loginTokens": []
}
},
"emails": [
{
"address": "dan@danyll.com",
"verified": false
}
]
}
Let's go through each field to get a better understanding.
让我们遍历每个领域以获得更好的理解。
The _id
field is a unique ID used to identify the document. You can provide this value, but if not, Meteor will generate a random alphanumeric string (e.g. e6AN2jGt9T9jrcwDt
). You can retrieve the _id
of a user by running Meteor.userId()
.
_id
字段是用于标识文档的唯一ID。 您可以提供此值,但如果不提供,Meteor将生成一个随机的字母数字字符串(例如e6AN2jGt9T9jrcwDt
)。 您可以通过运行Meteor.userId()
检索用户的_id
。
The createdAt
field stores an ISODate
data type of when the user was created. This is not a valid JSON datatype, and is one of the reasons Mongo uses BSON instead of JSON.
所述createdAt
字段存储一个ISODate
用户创建时的数据类型。 这不是有效的JSON数据类型,也是Mongo使用BSON而不是JSON的原因之一。
The services
field contains data that are required for the account service providers. Right now, it is an object with a password
field, because we are using the accounts-password
package. Later on when we add the accounts-github
package, you'll see the github
field being written inside the services
property. The services.resume
property keeps track of all the login sessions the user has.
services
字段包含帐户服务提供商所需的数据。 现在,这是一个带有password
字段的对象,因为我们使用的是accounts-password
软件包。 稍后,当我们添加accounts-github
程序包时,您将看到在services
属性内编写的github
字段。 services.resume
属性跟踪用户拥有的所有登录会话。
The emails
field specifies all the emails that belongs to a user. In the Accounts system, each email can only belong to one user.
emails
字段指定了属于用户的所有电子邮件。 在“帐户”系统中,每封电子邮件只能属于一个用户。
配置帐户用户界面 (Configuring the Accounts UI)
At the moment, a user can sign up with just an email and password. But mimicking Slack, we want each user to have a username as well as an email address. This is easily done by configuring Accounts.ui
. You may put this inside any client-side code.
目前,用户只能使用电子邮件和密码进行注册。 但是模仿Slack,我们希望每个用户都有一个用户名和一个电子邮件地址。 通过配置Accounts.ui
可以轻松完成此操作。 您可以将其放在任何客户端代码中。
Accounts.ui.config({
passwordSignupFields: 'USERNAME_AND_EMAIL'
});
And now when we create a new user, we see the username
field in the document.
现在,当我们创建一个新用户时,我们会在文档中看到username
段。
Apart from
USERNAME_AND_EMAIL
, there's also theUSERNAME_AND_OPTIONAL_EMAIL
,USERNAME_ONLY
andEMAIL_ONLY
options.EMAIL_ONLY
is the default.除了
USERNAME_AND_EMAIL
之外,还有USERNAME_AND_OPTIONAL_EMAIL
,USERNAME_ONLY
和EMAIL_ONLY
选项。EMAIL_ONLY
是默认设置。
The accounts-base
package will check the username
field to ensure it's unique, as well as check the email has not already been used by another user, before inserting into the users
collection.
基于accounts-base
软件包将在插入users
集合之前,检查username
段以确保其唯一性,并检查其他用户尚未使用的电子邮件。
The
accounts-ui
package provides the login form, as well as calling methods to register/login our users. But for production applications, you might want to create your own UI and set your own account management logic. To do that, you must call the Accounts API and Passwords API yourself. For example, you'd manually callAccounts.createUser()
to create the user, and customize the creation logic withAccounts.onCreateUser()
accounts-ui
软件包提供了登录表单,以及用于注册/登录用户的调用方法。 但是对于生产应用程序,您可能需要创建自己的UI并设置自己的帐户管理逻辑。 为此,您必须自己调用Accounts API和Passwords API 。 例如,您将手动调用Accounts.createUser()
创建用户,并使用Accounts.onCreateUser()
自定义创建逻辑
第三方整合 (Third-Party Integration)
How many usernames and passwords must you keep on top of your head? Even with passwords managers like LastPass, keeping track of another username / password set for our Slack clone might deter new users from signing up.
您必须掌握多少个用户名和密码? 即使使用LastPass之类的密码管理器, 也要跟踪为Slack克隆设置的另一个用户名/密码,这可能会阻止新用户注册。
So Meteor also provide package such as accounts-google
, accounts-facebook
, accounts-twitter
so you can log in with your existing Google, Facebook and Twitter accounts. One less thing to remember!
因此,Meteor还提供了accounts-google
, accounts-facebook
, accounts-twitter
等软件包,因此您可以使用现有的Google,Facebook和Twitter帐户登录。 要记住的少一件事!
的GitHub (GitHub)
Each third-party integration is a little different, but instructions should be clear. Here, we'll show you how to integrate with GitHub. Feel free to try it out with other services like Twitter or Facebook!
每个第三方集成都有些不同,但说明应清晰。 在这里,我们将向您展示如何与GitHub集成。 随意尝试使用其他服务,如Twitter或Facebook!
Let's add the accounts-github
package.
让我们添加accounts-github
程序包。
$ meteor add accounts-github
For your application to use GitHub for logging users in, it must be registered to an account. So go to your application and open up the login UI. Click the red button and follow the instructions set it up.
为了使您的应用程序能够使用GitHub登录用户,必须将其注册到一个帐户。 因此,转到您的应用程序并打开登录UI。 单击红色按钮,然后按照说明进行设置。
And now we can login using our GitHub account. The data required for this is stored under the github
property of services
.
现在,我们可以使用我们的GitHub帐户登录了。 所需的数据存储在services
的github
属性下。
...
"services": {
"github": {
"id": 3571481,
"accessToken": "2D58E69740CAD0FC1721970A1FF6A140A1A76A41",
"email": "dan@danyll.com",
"username": "d4nyll"
}
...
},
...
Once the user is logged in, you will also see that reflected in the GitHub Applications tab.
用户登录后,您还将在GitHub Applications选项卡中看到这一点。
确认邮件 (Confirmation Email)
When you sign up to most online services these days, you get a confirmation email.
这些天,当您注册大多数在线服务时,您会收到一封确认电子邮件。
We can enable this through Accounts.config
(note that it's not Accountsa.ui.config
).
我们可以通过Accounts.config
启用它(请注意,它不是Accountsa.ui.config
)。
/server/accounts.js
/server/accounts.js
Accounts.config({
sendVerificationEmail: true
});
This will internally call the Accounts.sendVerificationEmail()
on accounts creation.
这将在创建Accounts.sendVerificationEmail()
在内部调用Accounts.sendVerificationEmail()
。
You must call
Accounts.config
only on the server, since all mail are sent from the server. Specifying it in client code means no emails will be sent.您必须仅在服务器上调用
Accounts.config
,因为所有邮件都是从服务器发送的。 在客户端代码中指定它意味着不会发送电子邮件。
But to send the email, Meteor needs to be hooked up to a mail server. To do that we need the email
package provided by the core.
但是要发送电子邮件,Meteor需要连接到邮件服务器。 为此,我们需要核心提供的email
包。
$ meteor add email
The email
package reads the MAIL_URL
environment variable for the address of the SMTP server. If you use meteor deploy
, the app will automatically uses an account provided by Mailgun to send your emails.
email
程序包将读取MAIL_URL
环境变量以获取SMTP服务器的地址。 如果您使用meteor deploy
,则该应用程序将自动使用Mailgun提供的帐户发送电子邮件。
If no MAIL_URL
variable is set, the mail that would have been sent is output to the console.
如果未设置MAIL_URL
变量, 则将已发送的邮件输出到控制台。
I20150525-19:38:08.837(8)? ====== BEGIN MAIL #0 ======
I20150525-19:38:08.839(8)? To: dan@danyll.com
I20150525-19:38:08.839(8)? Subject: How to verify email address on localhost:3000
I20150525-19:38:08.840(8)? Content-Type: text/plain; charset=utf-8
I20150525-19:38:08.840(8)? Content-Transfer-Encoding: quoted-printable
I20150525-19:38:08.840(8)?
I20150525-19:38:08.840(8)? Hello,
I20150525-19:38:08.840(8)?
I20150525-19:38:08.840(8)? To verify your account email, simply click the link below.
I20150525-19:38:08.840(8)?
I20150525-19:38:08.840(8)? http://localhost:3000/#/verify-email/LooL9TcQj9qhCONfDwLLpCNNtrNs-FDeSsz6efqTrA-
I20150525-19:38:08.840(8)?
I20150525-19:38:08.840(8)? Thanks.
I20150525-19:38:08.840(8)?
I20150525-19:38:08.841(8)? ====== END MAIL #0 ======
I20150525-19:38:08.839(8)? (Mail not sent; to enable sending, set the MAIL_URL environment variable.)
I20150525-19:38:08.839(8)? MIME-Version: 1.0
I20150525-19:38:08.839(8)? From: "Meteor Accounts"
Notice the verification link provided - http://localhost:3000/#/verify-email/LooL9TcQj9qhCONfDwLLpCNNtrNs-FDeSsz6efqTrA-
If we go to that URL, it will run Accounts.onEmailVerificationLink()
, which verifies our email address.
请注意提供的验证链接http://localhost:3000/#/verify-email/LooL9TcQj9qhCONfDwLLpCNNtrNs-FDeSsz6efqTrA-
如果转到该URL,它将运行Accounts.onEmailVerificationLink()
来验证我们的电子邮件地址。
We can check this on the database.
我们可以在数据库上检查。
山d (Mandrill)
But we want to actually send the email! We must set up our own SMTP server, but we can also use services like Mailgun or Mandrill. Here, we will use Mandrill, but the logic is the same. So, let's set up an account on Mandrill.
但是我们实际上想发送电子邮件! 我们必须设置自己的SMTP服务器,但是我们也可以使用Mailgun或Mandrill之类的服务。 在这里,我们将使用Mandrill,但是逻辑是相同的。 因此,让我们在Mandrill上建立一个帐户 。
You'll be provided with some details about the SMTP server. Note that the value for MAIL_URL
has the syntax smtp://USERNAME:PASSWORD@HOST:PORT/
. Here we have all the information apart from the PASSWORD
:
您将获得有关SMTP服务器的一些详细信息。 请注意, MAIL_URL
的值的语法为smtp://USERNAME:PASSWORD@HOST:PORT/
。 除了PASSWORD
我们这里还有所有信息:
smtp://dan@danyll.com:PASSWORD@smtp.mandrillapp.com:587/
Click on + Add API Key
and a new key will be generated for you.
单击+ Add API Key
,将为您生成一个新密钥。
So now let's update our MAIL_URL
environment variable.
因此,现在让我们更新MAIL_URL
环境变量。
/server/mail.js
/server/mail.js
Meteor.startup(function () {
process.env.MAIL_URL = "smtp://dan@danyll.com:y3Z8TQxpxCiYsJJsCwyV0A@smtp.mandrillapp.com:587/";
};
Or if you want things clear over concise:
或者,如果您想让事情简洁明了:
Meteor.startup(function () {
smtp = {
username: 'dan@danyll.com',
password: 'y3Z8TQxpxCiYsJJsCwyV0A',
server: 'smtp.mandrillapp.com',
port: 587
};
process.env.MAIL_URL = 'smtp://' + encodeURIComponent(smtp.username) + ':' + encodeURIComponent(smtp.password) + '@' + encodeURIComponent(smtp.server) + ':' + smtp.port;
});
This time, the mail has been sent using Mailgun and to an actual recipient!
这次,已使用Mailgun将邮件发送给实际的收件人!
If you don't like the default email template, you can modify it using
Accounts.emailTemplates
如果您不喜欢默认的电子邮件模板,则可以使用
Accounts.emailTemplates
对其进行修改。
更新我们的应用程序 (Updating Our application)
Now that we have the idea of users, let's assign each message to the user that sent it. We will store the Meteor.userId
to get the ID of the current user.
现在我们有了用户的概念,让我们将每条消息分配给发送消息的用户。 我们将存储Meteor.userId
以获取当前用户的ID。
Messages.insert({
text: $('.input-box_text').val(),
user: Meteor.userId(),
timestamp: Date.now()
});
Meteor.userId()
will return the current user's id, and if no user is logged in, returnsnull
.
Meteor.userId()
将返回当前用户的ID,如果没有用户登录,则返回null
。
We are storing our users by ID, but when we display it, we'd really want to display their username. So let's create a helper function to do that.
我们通过ID存储用户,但是当我们显示它时,我们确实希望显示其用户名。 因此,让我们创建一个辅助函数来执行此操作。
Since this function might be used in more than one place, we'd use the Template.registerHelper()
function to define a helper function which can be used from all templates.
由于此函数可能在多个地方使用,因此我们将使用Template.registerHelper()
函数定义一个可在所有模板中使用的助手函数。
Template.registerHelper("usernameFromId", function (userId) {
var user = Meteor.users.findOne({_id: userId});
if (typeof user === "undefined") {
return "Anonymous";
}
if (typeof user.services.github !== "undefined") {
return user.services.github.username;
}
return user.username;
});
We will also do something similar so the time of the message is stored and displayed.
我们还将做类似的事情,以便存储和显示消息的时间。
Template.registerHelper("timestampToTime", function (timestamp) {
var date = new Date(timestamp);
var hours = date.getHours();
var minutes = "0" + date.getMinutes();
var seconds = "0" + date.getSeconds();
return hours + ':' + minutes.substr(minutes.length-2) + ':' + seconds.substr(seconds.length-2);
});
We will use the new properties and helper methods in our message
template.
我们将在message
模板中使用新的属性和辅助方法。
<div class="message">
<a href="" class="message_profile-pic"></a>
<a href="" class="message_username">{{usernameFromId user}}</a>
<span class="message_timestamp">{{timestampToTime timestamp}}</span>
<span class="message_star"></span>
<span class="message_content">{{text}}</span>
</div>
Now when you log in and post a message, your username and the timestamp when the message was posted is displayed.
现在,当您登录并发布消息时,将显示您的用户名和消息发布时的时间戳。
安全 (Security)
Great! Now we have user data - a big responsibility! We would need to keep this information secure.
大! 现在我们有了用户数据-一个很大的责任! 我们将需要确保此信息的安全。
When we created our example Meteor application, the autopublish
and insecure
packages were automatically added. autopublish
makes available all the data from all collections, and insecure
allows any user to insert into, update, and/or delete any documents.
创建示例流星应用程序时,会自动添加自动autopublish
和insecure
程序包。 autopublish
使所有集合中的所有数据可用,并且insecure
允许任何用户插入,更新和/或删除任何文档。
Why were these two packages included in the first place? Well, imagine I introduced the topic of subscription, publication, allow-deny rules, method calls, all before we were able to send one message! It'd been too much! So Meteor, by design, included those two packages to allow us to start building our application as quickly as possible. But to make our data secure, we must remove both packages.
为什么首先包含这两个软件包? 好吧,想象一下,在我们能够发送一条消息之前,我已经介绍了订阅,发布,允许拒绝规则,方法调用的主题! 太多了! 因此,Meteor在设计上包括了这两个软件包,以使我们能够尽快开始构建应用程序。 但是,为了确保我们的数据安全,我们必须删除两个软件包。
autopublish
(autopublish
)
If we run Meteor.users
in the console now, we get the records of all the users. Not great.
如果现在在控制台中运行Meteor.users
,我们将获取所有用户的记录。 不是很好。
$ meteor remove autopublish
You'll see all the messages on screen disappeared, that's because the data from the messages
collection is no longer being sent from the server.
您会看到屏幕上的所有消息都消失了,因为messages
集合中的数据不再从服务器发送。
If we run Meteor.users
now, we will only see, at most, the _id
, username
and profile
fields. We won't be able to get other users' data now.
如果现在运行Meteor.users
,则最多只能看到_id
, username
和profile
字段。 现在,我们将无法获取其他用户的数据。
But we want our messages to show. So let's publish it now server-side.
但是我们希望我们的消息能够显示。 因此,让我们现在在服务器端发布它。
/server/publications.js
/server/publications.js
Meteor.publish('messages', function () {
return Messages.find();
});
And now subscribe to the publication client-side.
现在,订阅发布客户端。
/client/app.js
/client/app.js
Meteor.subscribe('messages');
And now our messages are back! But the usernames have gone. So we must also publish certain fields from our users
collection too.
现在我们的信息又回来了! 但是用户名消失了。 因此,我们还必须发布users
集合中的某些字段。
/server/publications.js
/server/publications.js
Meteor.publish("allUsernames", function () {
return Meteor.users.find({}, {fields: {
"username": 1,
"services.github.username": 1
}});
});
/client/app.js
/client/app.js
Meteor.subscribe('allUsernames');
insecure
(insecure
)
If you open up your browser's console, and you run
如果打开浏览器的控制台,然后运行
Messages.find().fetch()
You can actually get the list of all the messages in the collection. What's more, find the _id
of one of the Objects
returned and run:
实际上,您可以获取集合中所有消息的列表。 此外,找到返回的Objects
之一的_id
并运行:
Messages.remove({_id: "tduWf5JMyJbX4w2Qj"})
Where tduWf5JMyJbX4w2Qj
is the _id
of the Object
.
其中tduWf5JMyJbX4w2Qj
是Object
的_id
。
The message has been removed! And not just on your local environment, but for everyone! Of course that's a big security hole.
该消息已被删除! 不仅在您当地的环境上,而且对于所有人! 当然,这是一个很大的安全漏洞。
Tthe insecure
package is just there to help us develop faster by allowing us to alter the server database on the client. Now we are not on training wheels anymore, we can remove it!
insecure
软件包可以帮助我们通过更改客户端上的服务器数据库来帮助我们更快地发展。 现在我们不再在训练轮上,可以将其卸下!
$ meteor remove insecure
But now if you try to send a message, this error comes up in the console:
但是现在,如果您尝试发送消息,则控制台中会出现此错误:
insert failed: Access denied
This is because we have now prevented the user from making changes to the collections. To get control over what actions the user is allowed to perform, we can either use Allow/Deny rules or Meteor methods.
这是因为我们现在阻止用户更改集合。 为了控制允许用户执行的操作,我们可以使用Allow / Deny规则或Meteor方法 。
允许否认 (Allow / Deny)
We can allow users to interact directly with the collection by setting allow rules.
通过设置允许规则,我们可以允许用户直接与集合进行交互。
Messages.allow({
insert: function (userId, doc) {
return true;
}
});
The collection.allow()
method specify which modifications are allowed from the client. Here, we are specifying that all inserts from any users are allowed on the Messages
collection, by returning true
.
collection.allow()
方法指定允许客户端进行哪些修改。 在这里,我们通过返回true
,指定在Messages
集合上允许来自任何用户的所有插入。
All looks innocent, but what we just did allows a user to insert a message masquerading as another user:
一切看起来都是无辜的,但是我们所做的只是允许用户插入伪装成其他用户的消息:
Messages.insert({
text: $('.input-box_text').val(),
user: "someoneElsesID",
timestamp: Date.now()
});
So our allow rule should really check that the userId
of the user matches the one specified int he document.
因此,我们的允许规则应确实检查用户的userId
是否与文档中指定的userId
匹配。
Messages.allow({
insert: function (userId, doc) {
return (userId && doc.user === userId);
}
});
As you can see, using allow/deny rules are quick and easy, but are prone to mistakes. Oh, and this also reminds me, I should check that the timestamp given is accurate...but how do we do that? What's to stop someone claim they posted a message predicting the lottery numbers an hour before the draw?
如您所见,使用允许/拒绝规则既快速又容易,但是容易出错。 哦,这也使我想起,我应该检查给出的时间戳是否正确...但是我们该怎么做? 阻止某人声称他们在开奖前一小时发布了一条消息,预测彩票号码是什么?
You can install the matb33:collection-hooks
and do something like this:
您可以安装matb33:collection-hooks
并执行以下操作:
Messages.before.insert(function (userId, doc) {
doc.timestamp = Date.now();
});
But this involves another package (Meteor doesn't support hooks natively). This is why I think using Meteor methods are easier in most cases.
但这涉及另一个包( Meteor本身不支持钩子 )。 这就是为什么我认为在大多数情况下使用Meteor方法更容易的原因。
方法 (Methods)
With Meteor methods, when the client wants to insert into the collection, it asks the server to do it. The server can then do some validation and set its own fields (such as message.timestamp
). This saves us having to check whether the timestamp provided by the client is accurate.
使用Meteor方法,当客户端要插入到集合中时,它将要求服务器执行此操作。 然后,服务器可以进行一些验证并设置自己的字段(例如message.timestamp
)。 这使我们不必检查客户端提供的时间戳是否正确。
/client/input.js
/client/input.js
Meteor.call('newMessage', {text: $('.input-box_text').val()});
/server/methods.js
/server/methods.js
Meteor.methods({
newMessage: function (message) {
message.timestamp = Date.now();
message.user = Meteor.userId();
Messages.insert(message);
}
})
All in all, I prefer using Meteor methods over allow/deny rules, mainly for these reasons:
总而言之,我更喜欢使用Meteor方法而不是允许/拒绝规则,主要是因为以下原因:
- Easier to do complicated validation - you explicitly determine what is allowed or not in the code 更容易进行复杂的验证-您明确确定代码中允许或不允许的内容
- All the code are in one block - no inserts on the client, setting allow / deny rules on both client and server, and hooks on the server 所有代码都在一个块中-客户端上无插入,在客户端和服务器上均设置了允许/拒绝规则,并在服务器上设置了挂钩
- Quite subjective, but I find methods less error-prone 相当主观,但我发现方法不太容易出错
Do you agree / disagree / still not sure? Start a discussion in the comments section!
您同意/不同意/仍然不确定吗? 在评论部分开始讨论!
存根 (Stubs)
But now, you might think, this defeats the purpose of latency compensation and the database everywhere principles of Meteor, since we must now wait for the server to confirm before the message shows up.
但是现在,您可能会认为,这违反了延迟补偿和Meteor无处不在数据库原则的目的,因为我们现在必须等待服务器确认,然后消息才会显示。
If we shut down our application now on the server, users won't see their messages on the message list.
如果我们现在在服务器上关闭应用程序,则用户将不会在消息列表中看到他们的消息。
But we can define a stub - the equivalent of a Meteor method that gets ran on the client-side. Taken from this Stack Overflow answer I provided a few months back.
但是我们可以定义一个存根-相当于在客户端上运行的Meteor方法。 几个月前,我从这个Stack Overflow答案中获取了答案 。
When the client calls the method, it will execute the stub method on the client-side, which can quickly return a (predicted) response. When the server comes back with the 'actual' response, it will replace the response generated by the stub and update other elements according.
当客户端调用该方法时,它将在客户端执行stub方法,该方法可以快速返回(预测的)响应。 当服务器返回“实际”响应时,它将替换存根生成的响应并根据其更新其他元素。
I'd usually create a /client/stubs.js
to house all the stub methods, but since there are no secret information we need to hide from the client, we can just move our /server/methods.js
to, say, /methods.js
我通常会创建一个/client/stubs.js
来容纳所有的stub方法,但是由于没有任何需要我们从客户端隐藏的秘密信息,因此我们可以将/server/methods.js
移至/methods.js
/client/stubs.js
/client/stubs.js
Meteor.methods({
newMessage: function (message) {
message.timestamp = Date.now();
message.user = Meteor.userId();
Messages.insert(message);
}
});
Now even when the server is down, the messages will still be rendered immediately on the client. And when the server is back up, the messages are still saved.
现在,即使服务器关闭,消息仍将立即在客户端上呈现。 并且,当服务器备份时,消息仍被保存。
翻译自: https://scotch.io/tutorials/building-a-slack-clone-in-meteor-js-part-3-authentication-and-security
meteor构建app程序