meteor构建app程序_在Meteor.js中构建Slack克隆(第3部分):身份验证和安全性

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-baseaccounts-password软件包提供登录,注销,帐户创建,电子邮件验证,密码恢复的功能。 还有accounts-uiaccounts-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集合。

An empty users collection

And now let's create a dummy user.

现在让我们创建一个虚拟用户。

Creating a dummy user using the UI provided by the accounts-ui package

And now we look back into our collection, we find an entry.

现在,我们回顾我们的收藏,我们找到一个条目。

The user entry as seen by Robomongo

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段。

An additional 'username' field shows up

Apart from USERNAME_AND_EMAIL, there's also the USERNAME_AND_OPTIONAL_EMAIL, USERNAME_ONLY and EMAIL_ONLY options. EMAIL_ONLY is the default.

除了USERNAME_AND_EMAIL之外,还有USERNAME_AND_OPTIONAL_EMAILUSERNAME_ONLYEMAIL_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 call Accounts.createUser() to create the user, and customize the creation logic with Accounts.onCreateUser()

accounts-ui软件包提供了登录表单,以及用于注册/登录用户的调用方法。 但是对于生产应用程序,您可能需要创建自己的UI并设置自己的帐户管理逻辑。 为此,您必须自己调用Accounts APIPasswords 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-googleaccounts-facebookaccounts-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。 单击红色按钮,然后按照说明进行设置。

meteor-github

github-new-oauth

And now we can login using our GitHub account. The data required for this is stored under the github property of services.

现在,我们可以使用我们的GitHub帐户登录了。 所需的数据存储在servicesgithub属性下。

...
"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选项卡中看到这一点。

github-slack-oauth

确认邮件 (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()来验证我们的电子邮件地址。

meteor-email-verified

We can check this on the database.

我们可以在数据库上检查。

meteor-email-verified-robo

山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上建立一个帐户

mandrill-signup

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 ,将为您生成一个新密钥。

mandrill-no-key

mandrill-new-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将邮件发送给实际的收件人!

email-received

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, returns null.

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.

现在,当您登录并发布消息时,将显示您的用户名和消息发布时的时间戳。

meteor-slack-username-time

安全 (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.

创建示例流星应用程序时,会自动添加自动autopublishinsecure程序包。 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 ,则最多只能看到_idusernameprofile字段。 现在,我们将无法获取其他用户的数据。

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.

其中tduWf5JMyJbX4w2QjObject_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程序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值