【问题标题】:Meteor session is undefined after page redirect页面重定向后流星会话未定义
【发布时间】:2017-07-24 05:51:49
【问题描述】:

我正在制作一个需要玩家大厅但没有帐户的游戏。有点像游戏,Spyfall。我正在使用 Meteor Sessions 来了解哪个玩家加入了大厅,以便我可以为该特定玩家返回正确的数据。我有一个 join.js 组件,用户在其中输入大厅访问代码和用户名。该组件还将用户重定向到大厅。 Join.js 位于路径 /join 处,而大厅位于路径 /:lobby 处。这是 join.js 的 handleSubmit 方法,它接受用户输入并将其放入玩家集合中:

    handleSubmit(event) {
    event.preventDefault();
    var party = Players.findOne({code: this.refs.code.value});
    if(typeof party !== 'undefined') {
        Meteor.call('players.insert', this.refs.code.value, this.refs.name.value);
        var playerId = Players.findOne({"name": this.refs.name.value})._id;
        Meteor.call('players.current', playerId);
        location.href = "/" + this.refs.code.value;
    } else {
        document.getElementById("error").innerHTML = 'Please enter a valid party code';
    }

我正在使用 player.js 集合中 Meteor.methods 中的 Sessions 来获取当前用户。

import { Mongo } from 'meteor/mongo';
import { Session } from 'meteor/session';

Meteor.methods({
    'players.insert': function(code, name) {
        console.log('adding player: ', name , code);
        Players.insert({code: code, name: name});
    },
    'players.updateAll': function(ids, characters, banners, countries, ancestors) {
        for (var i = 0; i < characters.length; i++){
            Players.update({_id: ids[i]}, {$set: {character: characters[i], banner: banners[i], country: countries[i], ancestor: ancestors[i]},});
        }
    },
    'players.current': function(playerId) {
            Session.set("currentPlayer", playerId);
            console.log(Session.get("currentPlayer"));
    },
    'players.getCurrent': function() {      
            return Session.get("currentPlayer");
    }
});

export const Players = new Mongo.Collection('players');

'players.current' 方法中的 console.log 返回正确的玩家 ID,但是一旦页面重定向到 /:lobby,players.getCurrent 返回未定义。我希望 players.getCurrent 返回与 console.log 返回相同的值。我该如何解决这个问题?这是在 lobby.js 中获取当前玩家 id 的函数:

getCurrentPlayerId() {
    return Meteor.call('players.getCurrent');
}

【问题讨论】:

    标签: javascript mongodb session meteor


    【解决方案1】:

    我认为问题在于您正在使用

    location.href = "/" + this.refs.code.value;
    

    而不是使用

    Router.go("/"+this.refs.code.value);
    

    如果使用 Iron Router。这样做就好像您正在刷新页面一样。这是a package to maintain Session variables across page refreshes

    【讨论】:

    • 我正在使用 React 路由器。 Router.go("/"+this.refs.code.value); 还能用吗?
    • 我会这么认为。你可以试试看。我没有使用过 React Router。您还应该考虑@jordanwillis 建议在服务器上处理更多。我可能会选择不带密码包的以帐户为基础的包。这样你就可以只用 Meteor.userId() 来处理当前用户。
    【解决方案2】:

    根据Meteor API,Meteor 方法旨在成为您定义从客户端调用的服务器端行为的方式。它们实际上是在服务器上定义的。

    方法是 Meteor 客户端可以通过 Meteor.call 调用的远程函数。

    在客户端定义的 Meteor 方法只是充当存根。

    在客户端调用方法定义与同名服务器方法关联的存根函数

    根据您的代码,您似乎在做客户端的所有事情。实际上,session 是 Meteor 客户端 API 的一部分(不能在服务器上使用)。

    Session 在客户端提供一个全局对象,您可以使用它来存储任意一组键值对。

    因此,如果我是你,我会在某种 util 文件中实现所有这些逻辑,然后你可以将其导入到需要它的模板中。您实际上是在做同样的事情,您只需要使用常规函数而不是 Meteor 方法。

    这是一个示例 util 文件(请务必根据项目的文件结构更新 Players 导入)。

    import { Players } from './players.js';
    import { Session } from 'meteor/session';
    
    export const players = {
      insert: function(code, name) {
        console.log('adding player: ', name , code);
        return Players.insert({code: code, name: name});
      },
    
      updateAll: function(ids, characters, banners, countries, ancestors) {
        for (var i = 0; i < characters.length; i++) {
          Players.update({_id: ids[i]}, {$set: {character: characters[i], banner: banners[i], country: countries[i], ancestor: ancestors[i]},});
        }
      },
    
      setCurrent: function(playerId) {
        Session.set("currentPlayer", playerId);
        console.log(Session.get("currentPlayer"));
      },
    
      getCurrent: function(unixTimestamp) {
        return Session.get("currentPlayer");
      },
    };
    

    然后,您可以将其导入到您拥有的任何模板中,该模板定义了您在问题中包含的事件处理程序。

    import { Template } from 'meteor/templating';
    import { players } from './utils.js';
    
    Template.template_name.events({
      'click .class': handleSubmit (event, instance) {
        event.preventDefault();
        var party = Players.findOne({code: this.refs.code.value});
    
        if (typeof party !== 'undefined') {
            var playerId = players.insert(this.refs.code.value, this.refs.name.value);
            players.setCurrent(playerId);
            location.href = "/" + this.refs.code.value;
        } else {
            document.getElementById("error").innerHTML = 'Please enter a valid party code';
        }
      },
    });
    

    当然,您需要修改上述代码以使用正确的模板名称和 utils 文件的位置。

    【讨论】:

    • util 文件会替换我所有的流星方法,还是只替换那些涉及会话的方法?
    • @nickkt 确定使用会话的任何内容,然后可以在客户端上运行的任何内容(因为流星方法适用于服务器端)
    • @nickkt 基本上任何“受保护的代码”都应该在流星方法中定义(仅放置在您的服务器代码中)。集合插入通常是受保护的代码,一旦您删除默认的 insecure 包,甚至无法在客户端上运行(除非您已相应地配置了允许/拒绝规则)
    猜你喜欢
    • 1970-01-01
    • 2020-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 1970-01-01
    • 2017-09-11
    • 1970-01-01
    相关资源
    最近更新 更多