Giter Site home page Giter Site logo

leanengine-node-sdk's Introduction

LeanEngine Node.js SDK

安装

npm install --save leanengine leancloud-storage@3 --save

建议使用 Node.js 8.0 以上的版本(可在 package.json 中设置 engines.node8.x)。

文档

项目示例

历史版本

Releases

若有意参与开发请看 CONTRIBUTING.md

leanengine-node-sdk's People

Contributors

aisk avatar jwfing avatar jysperm avatar killme2008 avatar leeyeh avatar sdjcw avatar wangxiao avatar weakish avatar ym avatar zenozeng avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

leanengine-node-sdk's Issues

beforeSave hook导致object内容错误

在数据库中,有beforeSave hook的新创建的User是这样的:

{
  "result": {
    "email": "xxxxxxxx",
    "username": "xxxx",
    "emailVerified": false,
    "__before": 1432921032633,
    "mobilePhoneVerified": false,
    "somecustomattr": "somevalue"
  },
  "ACL": {
    "*": {
      "write": true,
      "read": true
    }
  },
  "objectId": "5568a3c8e4b0a9a97408bfbe",
  "createdAt": "2015-05-30T01:37:12.676Z",
  "updatedAt": "2015-05-30T01:37:12.676Z"
}

回滚LeanEngine SDK 仍然 出现此问题。

回滚到CloudCode 2.0版本,没有 出现此问题。

使用在线定义函数,没有 问题。

猜测是由于beforeSave返回的数据格式不对,不应该带有{"result": data}.

在leanengine/lib/leanengine.js中:

beforeSave hook中将obj返回给callback:

324       Cloud.__code[hook + className]({
325         user: user,
326         object: obj
327       }, {
328         success: function() {
329           if ('__before_delete_for_' === hook) {
330             return cb(null, {});
331           } else {
332             return cb(null, obj);
333           }
334         },
335         error: function(err) {
336           cb(new Error(err));
337         }
338       });

这个callback在此定义:

196       var cb = function(err, data) {
197         if (err) {
198           return respError(res, err);
199         }
200         return resp(res, data);
201       };

resp返回{"result": data},将刚创建的object给返回了

247 var resp = function(res, data) {
248   res.setHeader('Content-Type', 'application/json; charset=UTF-8');
249   res.statusCode = 200;
250   return res.end(JSON.stringify({"result": data}));
251 };

高并发跳号问题

leanengine-node-sdk/lib/av-extra.js

AV.User._saveCurrentUser = function(user) {
  debug('_saveCurrentUser %s', user.get('username'));
  if (process.domain) {
    if (process.domain._currentUser === user) {
      return;
    }
    if (process.domain._currentUser) {
      AV.User.logOut();
    }
    if (user) {
      user._isCurrentUser = true;
    }
    process.domain._currentUser = user;
    return;
  }
  throw new Error('请添加 AV.Cloud.CookieSession 中间件以支持 AV.User 的操作。');
};

先设置了_isCurrentUser在高并发情况下会导致串号

AV.User._saveCurrentUser = function(user) {
  debug('_saveCurrentUser %s', user.get('username'));
  if (process.domain) {
    if (process.domain._currentUser === user) {
      return;
    }
    if (process.domain._currentUser) {
      AV.User.logOut();
    }
    if (user) {
      process.domain._currentUser = user;
      user._isCurrentUser = true;
    }  
    return;
  }
  throw new Error('请添加 AV.Cloud.CookieSession 中间件以支持 AV.User 的操作。');
};

leanengine 里 hack 的 avoscloud-sdk 方法实现不一样

https://github.com/leancloud/leanengine-node-sdk/blob/master/lib/leanengine.js#L266

Cloud.run = function(name, data, options) {
  try {
    Cloud.__code[name]({params: data, user: AV.User.current()}, options );
  } catch (err) {
    console.log('Run function \'' + name + '\' failed with error:', err);
    options.error(err);
  }
};

这里返回的是 promise
https://github.com/leancloud/javascript-sdk/blob/master/lib/cloudfunction.js#L28

    run: function(name, data, options) {
      var request = AV._request("functions", name, null, 'POST',
                                   AV._encode(data, null, true));

      return request.then(function(resp) {
        return AV._decode(null, resp).result;
      })._thenRunCallbacks(options);
    },

导致我迁移后的代码都不能用了

Usage with koa?

koa needs a generator function.So I couldn't make it works like the example:

// cloud.js
var AV = require('leanengine');
AV.Cloud.define('hello', function(request, response) {
  response.success('Hello world!');
});
module.exports = AV.Cloud;
var koa = require("koa");
var cloud = require('./cloud');
var app = koa();
app.use(cloud);

module.exports = app

It throw an error:AssertionError: app.use() requires a generator function.

云函数提供 Promise 支持

之前曾在 https://github.com/leancloud/cloud-code/issues/756 讨论过,结论是因为 Promise 只能够表示「成功」和「不成功」两种状态,而我们的云函数实际上有「成功」、「失败」、「出现异常」三种情况。

目前云函数会用 domain 捕捉异步的异常,但因为 domian 本身的不确定性,在之后的 Node 版本中不好保证一定有效。@leeyeh 提议支持用 Promise 去表示「出现异常」的情况,即也去捕捉通过 Promise 传递出的异常,保持和同步异常一样的处理方式。

有关实现不依赖 domain 的用户状态管理的几种方案

每次操作都需要传 sessionToken 参数

var Topic = AV.Object.extend('Topic');

AV.Cloud.define('func', function(request, response) {
  var query = new AV.Query(Topic);
  query.find({
    sessionToken: request.user._sessionToken,
    success: function(results) {
      response.success(results);
    }
  })
});

实现简单、容易理解;但用户需要修改现有代码,很容易遗漏某些地方,需要在函数间传递 user.

为每个请求提供一个 AV 实例

AV.Cloud.define('func', function(request, response) {
  var Topic = request.AV.Object.extend('Topic');
  var query = new AV.Query(Topic);
  query.find({
    success: function(results) {
      response.success(results);
    }
  })
});

可以通过改写 AV._request 来实现,用户需要修改一部分代码,也需要在函数间传递 AV.

向普通 Express 路由提供 parse authInfo 和 authorization 的支持

有用户希望在普通 Express 路由中使用这两个中间件(

// parse authInfo
Cloud.use(route, function(req, res, next) {
var appId, appKey, masterKey, contentType, param, prod, prodHeader, prodValue, sessionToken;
contentType = req.headers['content-type'];
if (/^text\/plain.*/i.test(contentType)) {
if (req.body && req.body !== '') {
req.body = JSON.parse(req.body);
}
appId = req.body._ApplicationId;
appKey = req.body._ApplicationKey;
masterKey = req.body._MasterKey;
prodValue = req.body._ApplicationProduction;
sessionToken = req.body._SessionToken;
for (param in req.body) {
if (param.charAt(0) === '_') {
delete req.body[param];
}
}
prod = 1;
if (prodValue === 0 || prodValue === false) {
prod = 0;
}
req.AV = {
id: appId,
key: appKey,
masterKey: masterKey,
prod: prod,
sessionToken: sessionToken
};
} else {
appId = req.headers['x-lc-id'] ||
req.headers['x-avoscloud-application-id'] ||
req.headers['x-uluru-application-id'];
appKey = req.headers['x-lc-key'] ||
req.headers['x-avoscloud-application-key'] ||
req.headers['x-uluru-application-key'];
masterKey = req.headers['x-avoscloud-master-key'] || req.headers['x-uluru-master-key'];
prodHeader = req.headers['x-lc-prod'] ||
req.headers['x-avoscloud-application-production'] ||
req.headers['x-uluru-application-production'];
sessionToken = req.headers['x-lc-session'] ||
req.headers['x-uluru-session-token'] ||
req.headers['x-avoscloud-session-token'];
prod = 1;
if (prodHeader === '0' || prodHeader === 'false') {
prod = 0;
}
if (appKey && (appKey.indexOf(',master') > 0)) {
masterKey = appKey.slice(0, appKey.indexOf(','));
appKey = null;
}
req.AV = {
id: appId,
key: appKey,
masterKey: masterKey,
prod: prod,
sessionToken: sessionToken
};
}
return next();
});
// authorization
Cloud.use(route, function(req, res, next) {
var key, master, requestSign, sign, timestamp, validSign, _ref;
if (!req.AV.id) {
return unauthResp(res);
}
if (AV.applicationId === req.AV.id &&
(AV.applicationKey === req.AV.key ||
AV.masterKey === req.AV.key ||
AV.masterKey === req.AV.masterKey)) {
if (AV.masterKey === req.AV.masterKey) {
req.AV.authMasterKey = true;
}
return next();
}
requestSign = req.headers['x-lc-sign'] || req.headers['x-avoscloud-request-sign'];
if (requestSign) {
_ref = requestSign.split(',');
sign = _ref[0];
timestamp = _ref[1];
master = _ref[2];
key = master === 'master' ? AV.masterKey : AV.applicationKey;
validSign = signByKey(timestamp, key);
if (validSign === sign.toLowerCase()) {
if (master === 'master') {
req.AV.authMasterKey = true;
req.AV.masterKey = key;
} else {
req.AV.key = key;
}
return next();
}
}
return unauthResp(res);
});
),可以考虑将 leanengine.js 中主要的中间件都拆分到单独的文件,以便用户可以自行使用。

支持 beforeUpdate

类似 beforeSave,约定保持一致,只是名字换了

@sdjcw

今天凌晨上线。

beforeSave 的 request.object 是将更新作用到当前对象后的临时新对象,它不保证是对象更新后的状态,而只是“当时”的最新状态。

koa 发起save请求 提示 response: { error: 'Config not found.' }

我想知道这个配置文件是什么 我在函数初始化时候已经传入了必要参数

除了模块依赖之外。
的代码
//init leanCloud
lg.init({
    appId: process.env.LEANCLOUD_APP_ID || 'GcEEi4mef5f6LjXb....省略',
    appKey: process.env.LEANCLOUD_APP_KEY || 'PI2khm4E6....省略',
    masterKey: process.env.LEANCLOUD_APP_MASTER_KEY || '1EXlsv8....省略'
});
lg.Cloud.useMasterKey();

// 声明一个 Todo 类型
var Todo = lg.Object.extend('Todo');
// 新建一个 Todo 对象
var todo = new Todo();
todo.set('title', '工程师周会');
todo.set('content', '每周工程师会议,周一下午2点');
todo.save().then(function(todo) {
    // 成功保存之后,执行其他逻辑.
    console.log('New object created with objectId: ' + todo.id);
}, function(error) {
    // 异常处理
    console.error(error);
});


指定 avoscloud-sdk 为 peerDependency

由用户自己安装维护 avoscloud-sdk 的版本,避免出现现在 sdk 会自动升级的问题。

leanengine-sdk 本身不再持有 AV,需要用户初始化传进来:

var AV = require('leanengine')(require('avoscloud-sdk'));

统计调用存储服务的请求

记录包括:请求次数,响应时间,响应码等信息。

分为 5 秒钟的实时信息和 5 分钟的持久化信息。

梳理调用 response.error 时指定 code 的逻辑并补充文档

因为 JS SDK 取消了 AV.Error:

AV.Error() is deprecated, and will be removed in next release.

很多用户会疑惑应该如何在 response.error 时指定 code,目前的替代方案是(注意是 message 而不是 error):

response.error({"code":"4444","message":"请先登录!"})

可能需要改进一下这个 API(例如将 code 作为第二个参数)并补充到文档上。

Node SDK 2.0 计划

主要是为了在更新 JavaScript SDK 2.0 的时候顺便做一些不兼容的修改,尽量能够在一个月内发布:

  • 更新 JavaScript SDK 2.0(不兼容,小程序相关支持)
  • 移除 AV.Cloud.httpRequest(不兼容)
  • 云函数 Promise 支持、移除 domain、onError(少量不兼容) #90 #67 #96
  • 向 res.saveCurrentUser 传入没有 sessionToken 的用户时需要向用户发出警告(细微不兼容) #80
  • 不正确的云函数名称、重复的云函数抛异常(细微不兼容)

还有一些不太可能引起不兼容的修改,可以做也可以往后放一放:

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.