Meteor学习笔记

作者: IT小C | 来源:发表于2016-03-22 15:16 被阅读2153次

    Meteor是一个基于Nodejs+Websocket+MongoDB的Web应用程序开发平台。
    Metror的七个特性
    1.只有数据:不在网络上传输HTML,只传输数据并让客户端决定如何渲染
    2.一种语言:前后端接口统一使用js
    3.无处不在的数据库:客服端,服务器使用相同,透明的API访问数据库
    4.延迟补偿:客户端上使用预读和模式模拟技术,使它看起来与数据库的连接是零延迟的
    5.完整的响应式:默认实时模式,从数据库到模板的所有层面上,都要使事件驱动的接口有效
    6.包容一切:开源的,能与现有的工具和框架整合
    7.简单等于生产力

    Meteor 1.1开始,支持 Windows/MongoDB 3.0

    我们先以win7下的meteor安装为例
    安装器下载地址为:
    https://install.meteor.com/windows
    点击打开之后会自动下载安装,时间有点长,之后需要注册Meteor开发者账号,可以跳过


    这样就安装成功了

    通过在命令行输入

    meteor help

    可以查看所有的Meteor指令

    下面我们先来创建一个meteor项目

    meteor create mypro


    之后根据提示输入下列指令来启动meteor

    cd mypro
    meteor

    meteor会先启动proxy,再启动mongoDB,最后启动应用程序

    之后在浏览器输入http://localhost:3000/就可以访问meteor应用了

    虽然Meteor是基于nodejs的,但是nodejs的包不能直接在Meteor中使用,在Meteor目录下运行如下指令可以查看当前可用的包

    meteor list

    下面我们通过实例来分析meteor项目的结构,通过
    https://github.com/meteor/meteor
    下载meteor的源码,在examples里我们进入leaderboard目录,执行

    meteor

    在浏览器中打开这个项目


    这是一个简单的meteor应用,点击名字,下面会出现给这个人加5分的按钮,点击之后会加5分并且自动重新排序
    首先,我们看一下leaderboard.html
    Meteor默认使用Handelbars模板系统
    1.模板的加载

    {{> 模板名}}

    2.模板的定义

    <template name="模板名">...</template>

    3.遍历数据集合

    {{#each 集合名}}...{{/each}}

    4.判断

    {{#if 条件为真}}...{{/if}}.....{{#unless 条件为假}}...{{/unless}}
    {{#if 条件为真}}...{{/else}}...{{/if}}

    Meteor的数据操作共享和延迟补偿技术说明
    每个meteor客户端包含一个内存数据库缓存Minimongo,在操作客户端的数据变更时,其实是操作的Minimongo,同时客户端会向服务器发送一个变更请求,Meteor使用DDP(Distributed Data Protocol 分布式数据协议)来传递数据。
    Meteor有个机制,客户端向服务器端发起一个写操作时,会立即更新本地缓存而不必等待服务器的响应,如果服务器拒绝变更请求,Meteor会修正客户端缓存,这种技术就叫“延迟补偿”,客户端持有最新的数据,同时服务器对于变更请求有最终的定夺的权利。
    在客户端修改数据库确实方便,不过会有安全性问题,所以一般发布到生产环境会移除Meteor的autopublish和insecure包,它们能够模拟每个客户端对服务器上的数据拥有完全读/写权限的效果。

    下面来看一下核心代码leaderboard.js
    1._id规则

    Players = new Mongo.Collection("players");
    

    Meteor在MongoDB中生成的_id是17位的简化id,如果要用mongodb默认的24位id则可以通过

    new Meteor.Collection(name,{idGeneration:'MONGO'});
    

    也可以通过下列方法创建ObjectID

    new Meteor.Collection.ObjectID(hexString)
    

    2.客户端服务器运行不同的代码
    因为leaderboard.js是客户端和服务器都加载的,所以如果要判断是客户端的操作还是服务器端的操作需要通过

    if(Meteor.isClient){
        //客户端执行的代码
    }
    if(Meteor.isServer){
        //服务器端执行的代码
    }
    

    目录说明:
    服务器端

    JavaScript/所有js
    private/所有js
    server/所有js

    客户端

    client/所有js

    公用资源

    public/资源文件

    其他目录下的文件会被客户端和服务器端两者加载

    3.Meteor可以使用的数据库操作API

    find,findOne,insert,update,upsert,remove,allow,deny

    4.Session
    Session只能用于客户端

    Session.set(key,value);  //设置key的value
    Session.setDefault(key,value); //设置key默认的value
    Session.get(key) //获取key的value
    Session.equals(key,value) //判断key的值是否等于value
    

    5.startup
    Meteor.startup()是Meteor提供的核心API,可以用在客户端和服务器端,当用在服务器端时,会在服务器进程启动完毕后立即执行,客户端时,会在DOM准备就绪时立即执行。
    通常,Meteor.startup()用来做一些初始化的事情,比如往数据库里插入文档或从数据库读取文档并进行展示。

    Meteor信奉响应式编程的理念
    我们可以在控制台直接给Session赋值,就可以在页面上直接看到效果


    能够响应式计算的有

    Templates
    Meteor.render,Meteor.renderList
    Deps.autorun

    能够触发变化的响应式数据源有

    Session内的变量
    Collections内的数据库查询
    Meteor.status
    Meteor.subscribe内的ready()方法
    Meteor.user
    Meteor.userId
    Meteor.loggingIn

    insecure包
    模拟每个客户端对服务器上的数据库拥有完全读/写权限的效果,通常生产环境需要移除这个包

    meteor remove insecure

    这时如果给玩家加5分,会发现玩家排名和分数上移后又瞬间回到原样了,控制台显示update failed: Access denied


    这就是延迟补偿,去掉了insecure包,需要修改代码
    方法一
    在服务器端执行的代码增加

    Players.allow({
        update: function(userId,doc,fieldNames,modifier){
            return true;
        }
    });
    

    如果返回true,允许客户端执行update操作,false时拒绝,也可以使用collection.deny方法来拒绝客户端修改数据库的请求
    如果只允许得分大于30分的进行修改

    Players.allow({
        update: function(userId,doc,fieldNames,modifier){
            return doc.score >= 30 ? true : false;
        }
    });
    

    只有在客户端试图修改数据时才会触发,而服务器端不受这个限制

    方法二.
    通过Meteor.methods和Meteor.call的组合来实现客户端修改数据

    //server
    Meteor.methods({
        add5:function(selectedPlayer){
          Players.update(selectedPlayer,{$inc:{score:5}});
        }
    });
    
    //client
    Template.leaderboard.events({
        'click .inc': function () {
          Meteor.call('add5',Session.get("selectedPlayer"));
        }
    });
    

    autopublish包
    使用autopublish包,Meteor会客户端Minimongo中的内容和服务器端的MongoDB同步(除了users集合部分的内容和索引)通常生产环境也需要移除这个包

    meter remove autopublish

    这时候客户端和服务器端的数据库就不同步了,需要修改代码

    //server
    Meteor.publish("leaderboard",function(){
        return Players.find();
    });
    
    //client
    Meteor.subscribe("leaderboard");
    

    这样就可以了,假如我们有多个集合,可以选择性地从服务器端发布,然后从客户端订阅
    Meteor.publish只能用于服务器端
    Meteor.subscribe只能用于客户端

    这里要说一下,leaderboard.js所有的修改之后Meteor服务器会自动重启应用,这样就能看到最新的修改结果,还是很方便的

    Meteor文件的加载顺序

    lib目录下的文件先加载
    main.*的文件最后加载
    子目录的文件在根目录的文件之前加载
    同目录的文件按文件名的字母顺序加载

    下面我们以搭建一个微博为例子来讲解需要注意的地方

    我们采用的meteor组件是jquery+bootstrap+backbone+accounts-password
    Meteor添加包
    Meteor添加bootstrap依赖包

    meteor add bootstrap

    无须在<head>中引入bootstrap即可使用它,也无需引用jquery,jquery已经内置在Meteor的核心包中

    在Meteor的页面里必须包含head,body标签,不然会报错,在template模板页面里不需要

    我们不用在html页面里引入只含有template标签的模板页面,因为Meteor会将每个模板转化成js函数并加载它们

    添加backbone包来实现路由功能

    meteor add backbone

    backbone的详细使用可以参考
    http://backbonejs.org/
    这里需要注意meteor session的用法
    session只能用于客户端,当session值改变时,如果需要更新页面,需要在helpers里返回

    Session.setDefault("currentUrl",{index:"active",reg:""});
    var urlRouter = Backbone.Router.extend({
        routes:{
            "":"index",
            "reg":"reg"
        },
        index:function(){
            console.log("index");
            Session.set("currentUrl",{index:"active",reg:""});
    
        },
        reg:function(){
            console.log("reg");
            Session.set("currentUrl",{index:"",reg:"active"});
        },
        redirect:function(url){
            this.navigate(url,true);
        }
    });
    
    Router = new urlRouter;
    
    Template.container.helpers({
        currentUrl: function () {
            return Session.get('currentUrl');
        }
    });
    
    Meteor.startup(function(){
        Backbone.history.start({pushState:true});
    });
    

    这样在html里才能访问到currentUrl

    {{#if currentUrl.index}}
        {{> index}}
    {{/if}}
    {{#if currentUrl.reg}}
        {{> reg}}
    {{/if}}
    

    还有一种方法是直接通过模板名下的变量名来返回,但是浏览器会警告

    Template.info.info = function(){
        return Session.get("info");
    }
    

    添加accounts-password包构建用户认证系统,他可以帮助你快速的完成用户的注册,登陆

    meteor add accounts-password

    Template.reg.events({
        'click #submit': function(e){
            e.preventDefault();
            Accounts.createUser({username:$("#username").val(),password:$("#password").val()});
        }
    });
    

    这样就会在数据库中保存用户名和密码,密码是经过SRP加密的


    {{currentUser}}存储了当前在线用户的信息(其实是调用了Meteor.user()),可以用来判断用户是否在线,不在线返回null

    {{#if currentUser}}
        <a href="/logout" class="btn btn-primary-large">退出</a>
    {{else}}
        <a href="/reg" class="btn btn-primary-large">注册</a>
    {{/if}}
    

    Meteor.userId()可以用来判断用户是否在线,存储当前在线用户的_id,不在线返回null

    logout:function(){
        if(Meteor.userId()){
            Meteor.logout();
            this.navigate("/",true);
            Session.set("info",{success:"退出成功",error:""});
        }else{
            this.navigate("/",true);
            Session.set("info",{success:"",error:"用户不在线"});
        }
    },
    

    Meteor.loginWithPassword可以实现用户登录功能

    Meteor.loginWithPassword($("#username").val(),$("#password").val(),function(err){
        if(err){
            Session.set("info",{success:"",error:err.reason});
        }else{
            Session.set("info",{success:"登陆成功",error:""});
            Router.redirect("/");
        }
    });
    

    如果密码错误,err.reason会返回


    如果用户不存在,err.reason返回


    这些认证判断都是Meteor为我们做好的

    Meteor对html标签的闭合要求是很高的,如果有没有闭合的标签,就会提示出错,还是很智能的

    如果我们在客户端的js文件里定义了数据集

    Posts = new Meteor.Collection("posts");
    

    之后直接调用insert方法会报错


    因为数据集在服务器端没有定义,我们需要的服务器端的js文件里也增加一句,然后可以通过allow来控制谁可以操作数据

    Posts = new Meteor.Collection("posts");
    Posts.allow({
        insert:function(userId,doc){
            return userId && (doc.user._id === userId);
        }
    });
    

    添加markdown支持
    Meteor提供了一个showdown包,只需将Markdown文本添加到{{#markdown}}...{{/markdown}}标签内

    meteor add showdown

    该Meteor微博的完整源码我已上传到Github上
    https://github.com/ccfromstar/meteor_weibo

    最后说一下Meteor的部署
    有两种方法
    1.部署到Meteor提供的免费服务器上

    meteor deploy weibocc.meteor.com


    删除站点重新部署,如果想清空数据库

    meteor deploy weibocc.meteor.com -D

    如果希望是自己私有的,可以设置一个密码,这样下次更新代码时候就需要密码才能更新

    meteor deploy weibocc.meteor.com -P

    2.将应用打包部署到自己的服务器上

    meteor bundle weibocc.tgz

    要运行这个应用,需要Nodejs和MongoDB

    PORT=3000 MONGO_URL=mongodb://localhost:27017/weibo node bundle/main.js

    这里需要注意的是我们必须重新编译fibers包

    cd bundle/programs/server/node_modules
    rm -r fibers
    npm install fibers@1.0.1

    这样就可以了

    相关文章

      网友评论

        本文标题:Meteor学习笔记

        本文链接:https://www.haomeiwen.com/subject/ozkclttx.html