Meteor:从客户端访问函数,在服务器上运行

时间:2016-03-26 21:23:11

标签: meteor methods public

我正在尝试创建一个使用Steam API的程序。我希望能够调用该方法从客户端检索用户的信息,同时保持方法的实际代码对客户端保密,因为它包含API密钥。我尝试在服务器文件夹中将方法定义为全局,如下所示:

key = 'xxxxxxxxxxxxxxxx';

Meteor.steamFunctions = {
    getName: function(user){
        var userSteamId = user.profile.id;
        Meteor.http.get('http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=' + key + '&steamids=' + userSteamId, function(error, resultJSON){
            if (error){
                return 'Error in Steam API';
            } else {
                var json = JSON.parse(resultJSON);
                return json.personaname;
            }
        })
    },

    getPic: function(user){
        var userSteamId = user.profile.id;
        Meteor.http.get('http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=' + key + '&steamids=' + userSteamId, function(error, resultJSON){
            if (error){
                return 'Error in Steam API';
            } else {
                var json = JSON.parse(resultJSON);
                return json.avatarfull;
            }
        })
    }
}

然后我尝试在客户端脚本中调用它:

if (Meteor.isClient){
    Template.profile.helpers({
        'getName': function(){
            return Meteor.steamFunctions.getName(Meteor.user());
        }
    });
}

然而,这会抛出

Exception in template helper: TypeError: Cannot read property 'getName' of undefined
    at Object.Template.profile.helpers.getName

如何在仍然访问数据的同时保持对用户的密钥保密?

2 个答案:

答案 0 :(得分:2)

嗯,这并不像向Meteor全局添加属性那么简单。此外,执行此操作的远程方法/调用API将涉及异步代码。

使用秘密API密钥在服务器端调用API,只能在服务器上看到代码,例如: ./server子目录。在服务器端定义Meteor.method,可以在客户端使用Meteor.call进行调用。

在服务器端Meteor方法中,您可以method security checks检查登录的用户或用户ID,并使用此方法来决定是进行呼叫还是忽略请求。如果请求不正确或出现错误,您可以从服务器端抛出新的Meteor.Error,但这些需要资源进行通信。

关于Meteor的理解是,改变Javascript在浏览器或服务器上的行为方式并没有什么神奇之处。服务器最终运行nodejs。在服务器上定义的对象不会神奇地迁移到客户端,反之亦然。如果在两者上定义了一个对象,它实际上是两个独立的代码片段。

因此,在客户端代码中,从浏览器调用服务器端代码的Meteor.call实际上是使用本质上异步的现有websocket或ajax API。这意味着您需要构建客户端代码以在浏览器上提供回调函数,以处理查找NamePic的异步返回结果。直接返回和命令式编码风格是不可能的。

通常,您希望根据查询返回的信息更新用户屏幕上的内容。通常的Meteor编码是让回调函数用Session.set()更新session global variable。模板可以引用这些会话变量,通过隐含或显式的Tracker.autorun(),可以在API返回数据时更新屏幕。

答案 1 :(得分:1)

你需要:

  1. 将您的steamFunctions移至仅在服务器上定义的methods
  2. 从客户端正确调用方法。
  3. 以下是基于原始问题的一些示例代码。请注意,这尚未经过测试,可能需要进行一些调整。

    服务器/ methods.js

    const KEY = 'xxxxxxxxxxxxxxxx';
    const URL = 'http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002';
    
    Meteor.methods({
      getName() {
        const userSteamId = Meteor.user().profile.id;
        const params = {
          key: KEY,
          steamids: userSteamId,
        };
    
        try {
          var result = HTTP.get(URL, { params });
    
          // Double check this - I have no idea what this API returns. The value
          // you want may be nested under result, like result.data or something.
          return JSON.parse(result).personaname;
        } catch (e) {
          // Something bad happened - maybe throw an error.
          return false;
        }
      },
    });
    

    请注意,此方法是在服务器上定义的,因此我们不会将KEY公开给客户端。另请注意,我们使用的是HTTP api的同步版本,因此可以将值返回给客户端。

    <强>的客户机/ LIB / user.js的

    Tracker.autorun(function () {
      user = Meteor.user();
      if (user && user.profile && user.profile.id) {
        Meteor.call('getName', (err, name) => {
          Session.set('steamName', name);
        });
      } else {
        Session.set('steamName', '');
      }
    });
    

    当用户登录或更新时,获取蒸汽名称并设置全局会话变量。

    <强>的客户机/模板/ profile.js

    Template.profile.helpers({
      getName: function () {
        return Session.get('steamName');
      },
    });
    

    阅读steamName会话变量,以便在模板中使用。