全部产品

Node.js

更新时间:2017-08-25 16:28:32   分享:   

函数计算目前支持以下Nodejs运行环境:

  • Nodejs6.10 (runtime = nodejs6)

在函数计算服务使用Nodejs编程,需要定义一个Nodejs函数作为入口,一个最简单的函数定义如下:

  1. exports.handler = function(event, context, callback) {
  2. callback(null, 'hello world');
  3. };
  1. 函数名
    • exports.handler需要与创建函数时的”Handler”字段相对应:例如创建函数时指定的Handler为index.handler,那么函数计算会去加载index.js中定义的handler函数
  2. event参数
    • event参数是用户调用函数时传入的数据,其类型是Buffer
  3. context参数
    • context参数中包含一些函数的运行时信息(例如request id/临时AK等)。其类型是object,具体结构和使用在下面的使用context介绍
  4. callback参数
    • callback参数用于返回调用函数的结果,其签名是function(err, data),与Nodejs中惯用的callback一样,它的第一个参数是error,第二个参数data。如果调用时err不为空,则函数将返回HandledInvocationError,否则将返回data的内容。如果data是Buffer类型则它的数据将直接被返回,如果data是object,则会将其转换成JSON字符串返回,其他类型将被转换成string返回。

进阶使用

使用event

event是用户调用函数时传入的数据,函数计算不对它的内容进行任何解释,传递给函数的event是Buffer类型。用户在函数中可以根据实际情况对event进行转换:例如输入数据是一个JSON string的话,用户可以把它转换成一个object:

  1. exports.handler = function(event, context, callback) {
  2. var eventObj = JSON.parse(event.toString());
  3. callback(null, eventObj['key']);
  4. };

使用context

context是函数计算在运行时生成的一个对象,其中包含一些运行时的信息,用户在代码中可以使用这些信息。context的类型是object,其定义如下:

  1. {
  2. 'requestId': 'b1c5100f-819d-c421-3a5e-7782a27d8a33',
  3. 'credentials': {
  4. 'accessKeyId': 'STS.access_key_id',
  5. 'accessKeySecret': 'access_key_secret',
  6. 'securityToken': 'security_token',
  7. },
  8. 'function': {
  9. 'name': 'my-func',
  10. 'handler': 'index.handler',
  11. 'memory': 128,
  12. 'timeout': 10,
  13. },
  14. }

可以看到context中包含了3个信息:

  1. requestId: 本次调用请求的唯一id,用户可以把它记录下来在出现问题的时候方便调查
  2. function: 当前调用的函数的一些基本信息如函数名/函数入口/函数内存/超时时间
  3. credentials: 函数计算服务通过扮演用户提供的服务角色获得的一组临时密钥,其有效时间是5分钟。用户可以在代码中使用它去访问相应的服务(例如OSS),这就避免了用户把自己的AK信息写死在函数代码里。

例如下面的代码使用临时密钥,向OSS中上传了一个文件:

  1. var OSSClient = require('ali-oss').Wrapper;
  2. exports.handler = function(event, context, callback) {
  3. console.log(event.toString());
  4. var ossClient = new OSSClient({
  5. accessKeyId: context.credentials.accessKeyId,
  6. accessKeySecret: context.credentials.accessKeySecret,
  7. stsToken: context.credentials.securityToken,
  8. region: 'oss-cn-shanghai',
  9. bucket: 'my-bucket',
  10. });
  11. ossClient.put('my-object', new Buffer('hello, fc')).then(function(res) {
  12. callback(null, 'put object');
  13. }).catch(function(err) {
  14. callback(err);
  15. });
  16. };

使用logging

用户的函数通过console.log打印的内容会被收集到用户在创建Service时指定的LogStore中:

  1. exports.handler = function(event, context, callback) {
  2. console.info(null, 'hello world');
  3. callback(null, 'hello world');
  4. };

上面的代码输出的日志内容是:

  1. message:2017-07-05T05:13:35.920Z a72df088-f738-cee3-e0fe-323ad89118e5 [INFO] hello world

使用console.warnconsole.error分别可以打包WARN/ERROR级别的日志。

使用内置的模块

除了Nodejs的标准模块,函数计算的Nodejs运行环境中还包含了一些常用模块,用户可以直接引用,目前包含的模块有:

例如使用gm进行图片翻转的函数如下:

  1. var gm = require('gm').subClass({imageMagick: true});
  2. exports.handler = function(event, context, callback) {
  3. gm(event)
  4. .flip()
  5. .toBuffer('PNG',function (err, buffer) {
  6. if (err) return callback(err);
  7. callback(null, buffer);
  8. });
  9. };

注意,上面的函数直接使用event作为图片的二进制数据并且直接把生成的图片作为二进制数据返回。

使用自定义的模块

如果用户需要使用自定义的模块,则需要将它们与代码一起打包。下面将演示通过fcli添加一个访问mysql的模块mysql的步骤:

  1. 建立一个目录用于存放代码和依赖模块:

    1. mkdir /tmp/code
  2. 新建代码文件,例如/tmp/code/index.js,在代码中使用mysql:

    1. var mysql = require('mysql');
    2. exports.handler = function(event, context, callback) {
    3. var connection = mysql.createConnection({
    4. host : 'localhost',
    5. user : 'me',
    6. password : 'secret',
    7. database : 'my_db'
    8. });
    9. connection.connect();
    10. connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
    11. if (error) return callback(error);
    12. console.log('The solution is: ', results[0].solution);
    13. callback(null, results[0].solution);
    14. });
    15. connection.end();
    16. };
  3. 在/tmp/code目录下安装依赖:

    1. cd /tmp/code
    2. npm install mysql

    安装完成之后,/tmp/code目录的内容应该是这样:

    1. ls -l /tmp/code
    2. -rw-r--r-- 1 rockuw wheel 511 Aug 15 17:58 index.js
    3. drwxr-xr-x 13 rockuw wheel 442 Aug 15 18:01 node_modules
  4. 使用fcli创建函数并调用:

    1. ./fcli shell
    2. mkf my-func -h index.handler --runtime nodejs6 -d /tmp/code
    3. invk my-func

调用外部命令

用户的函数可能会用到一些工具,而这些工具并不是用Nodejs写的(例如shell脚本/C++或者go编译出来的可执行文件)。用户仍然可以将它们与代码一起打包,然后在函数中通过运行外部命令的方法来使用它们。下面的例子中演示了如何运行一个shell脚本:

  1. var exec = require('child_process');
  2. exports.handler = function(event, context, callback) {
  3. exec.exec('bash /code/script.sh', {}, function(err, stdout, stderr) {
  4. if (err) return callback(err);
  5. console.log(stdout, stderr);
  6. callback(null, stdout);
  7. });
  8. };

需要注意的是,使用C/C++/go编译出来的可执行文件,需要与函数计算的运行环境兼容。函数计算的Python运行环境是:

  • Linux内核版本:Linux 4.4.24-2.al7.x86_64
  • docker基础镜像:docker pull python:2.7

理解callback

Nodejs采用异步编程的模型,用户函数必须通过调用callback来返回数据或者错误。

1. 确保callback被调用

如果在函数中没有调用callback,则系统将认为函数没有结束,会等待函数结果直到超时。例如下面的函数调用时将收到超时错误:

  1. exports.handler = function(event, context, callback) {
  2. console.log('hello world');
  3. };

调用结果:

  1. {"errorMessage":"Function timed out after 3 seconds"}

2. callback被调用后则函数结束

callback被调用后函数就会停止运行,重复调用callback只接受第一次调用的结果;需确保所有任务在callback调用之前完成,否则它们将不会被运行。例如下面的函数,将返回”hello world”并且”message” 不会被打印:

  1. exports.handler = function(event, context, callback) {
  2. callback(null, 'hello world');
  3. callback(null, 'done');
  4. setTimeout(function() {
  5. console.log('message');
  6. }, 1000);
  7. };

错误处理

对于Nodejs运行环境的函数,用户可能收到两种错误,错误类型记录在返回的HTTP Header字段中(X-Fc-Error-Type):

  1. HandledInvocationError: 通过callback的第一个参数返回的错误
  2. UnhandledInvocationError: 其他错误,包括未接住的异常/超时/OOM等

示例1,返回HandledInvocationError:

  1. exports.handler = function(event, context, callback) {
  2. callback(new Error('oops'));
  3. };

调用时收到的响应为:

  1. {
  2. "errorMessage": "oops",
  3. "errorType": "Error",
  4. "stackTrace": [
  5. "at exports.handler (/code/index.js:2:12)"
  6. ]
  7. }

示例2,返回UnhandledInvocationError:

  1. exports.handler = function(event, context, callback) {
  2. throw new Error('oops');
  3. };

调用时收到的响应为:

  1. {"errorMessage":"Process exited unexpectedly before completing request"}
本文导读目录
本文导读目录
以上内容是否对您有帮助?