函数计算目前支持Node.js 6.x、Node.js 8.x、Node.js 10.x、Node.js 12.x和Node.js 14.x运行环境。本文介绍了Node.js运行环境的日志、函数、错误、模块使用和外部命令调用等内容。

打印日志

您的函数通过console.log打印的内容会被收集到创建服务时指定的Logstore中。函数日志的更多信息,请参见配置日志。按需执行以下命令,获取日志或打印日志:
  • 执行以下命令获取日志。
    exports.handler = function (event, context, callback) {
        console.info('hello world');
        callback(null, 'hello world');
    };            
    输出的日志内容如下。
    message:2017-07-05T05:13:35.920Z a72df088-f738-cee3-e0fe-323ad891**** [INFO] hello world           
    您还可以通过接口setLogLevel来指定打印日志的级别,其中日志级别从高到低如下所示。
    日志级别 对应接口
    error console.error
    warn console.warn
    info console.info
    verbose console.log
    debug console.debug
  • 执行以下代码,打印不同级别的日志。
    'use strict';
    exports.handler = function(evt, ctx, callback) {
        console.setLogLevel("error");
        console.error("console error 1");
        console.info("console info 1");
        console.warn("console warn 1");
        console.log("console log 1");
    
        console.setLogLevel("warn");
        console.error("console error 2");
        console.info("console info 2");
        console.warn("console warn 2");
        console.log("console log 2");
    
        console.setLogLevel("info");
        callback(null, evt);
    };            
    输出的日志内容如下。
    FC Invoke Start RequestId: 607ed187-9f2a-4506-a5b1-5a9785ca****
    load code for handler:index.handler
    2021-12-07T11:55:22.977Z 607ed187-9f2a-4506-a5b1-5a9785ca**** [error] console error 1
    2021-12-07T11:55:22.977Z 607ed187-9f2a-4506-a5b1-5a9785ca**** [info] console info 1
    2021-12-07T11:55:22.977Z 607ed187-9f2a-4506-a5b1-5a9785ca**** [warn] console warn 1
    2021-12-07T11:55:22.977Z 607ed187-9f2a-4506-a5b1-5a9785ca**** [verbose] console log 1
    2021-12-07T11:55:22.977Z 607ed187-9f2a-4506-a5b1-5a9785ca**** [error] console error 2
    2021-12-07T11:55:22.977Z 607ed187-9f2a-4506-a5b1-5a9785ca**** [info] console info 2
    2021-12-07T11:55:22.977Z 607ed187-9f2a-4506-a5b1-5a9785ca**** [warn] console warn 2
    2021-12-07T11:55:22.977Z 607ed187-9f2a-4506-a5b1-5a9785ca**** [verbose] console log 2
    FC Invoke End RequestId: 607ed187-9f2a-4506-a5b1-5a9785ca****

返回信息

Node.js采用异步编程的模型,您的函数需要使用callback入参返回信息。callback的语法如下所示。

callback(Error error, Object result);           
其中:
  • 可选:error:在函数执行内部失败时使用此参数返回错误内容,成功情况下设置为null。
  • 可选:result:使用此参数返回函数成功的执行结果。result可以是任意类型,函数计算会将其序列化成字节流,放到响应体中返回给调用方。
说明 根据调用函数时的调用类型不同,返回值会有不同的处理方式。同步调用的返回值将会序列化字节流返回给调用方,异步调用的返回值将会被抛弃,需要您将重要信息记录到日志中。
  • callback被调用后则函数结束

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

    exports.handler = function(event, context, callback) {
      callback(null, 'hello world');
      callback(null, 'done');
      setTimeout(function() {
        console.log('message');
      }, 1000);
    };          
  • callback未被调用则函数超时

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

    exports.handler = function(event, context, callback) {
      console.log('hello world');
    };            
    调用结果示例如下:
    {"errorMessage":"Function timed out after 60 seconds (maxMemoryUsage: 0MB)"} 

错误处理

对于Node.js运行环境的函数,您可能收到以下两种错误,错误类型记录在返回的HTTP Header字段中的X-Fc-Error-Type

  • HandledInvocationError:通过callback的第一个参数返回的错误。

    示例:

    执行以下命令调用callback命令。

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

    收到的响应如下所示。

    {
      "errorMessage": "oops",
      "errorType": "Error",
      "stackTrace": [
        "at exports.handler (/code/index.js:2:12)"
      ]
    }
  • UnhandledInvocationError:其他错误,包括未捕获异常、超时错误和OOM(Out of memory)错误等。

    当您的函数逻辑未捕获到错误时,函数计算系统会尽可能捕获错误,并返回具体的信息。当遇到系统无法捕获的错误时,例如您的函数在运行过程中突然崩溃退出,系统会返回一个通用的错误信息。

    exports.handler = function(event, context, callback) {
      throw new Error('oops');
    };
    收到的响应如下:
    {"errorMessage":"Process exited unexpectedly before completing request"}

更多错误类型相关信息,请参见错误处理

使用内置模块

除了Node.js的标准模块,函数计算的Node.js运行环境中还包含了一些常用模块,您可以直接引用这些常用模块,目前函数计算包含的常见模块如下所示。

模块名称 版本 模块介绍
co 4.6.0 控制流
gm 1.23.0 图片处理库
ali-oss 4.10.1 OSS SDK
ali-mns 2.6.5 MNS SDK
tablestore 4.2.0 OTS SDK
aliyun-sdk 1.10.12 Aliyun SDK
@alicloud/fc2 2.1.0 函数计算SDK
opencv 6.0.0 视觉算法库
body 5.1.0 HTTP body解析库
raw-body 2.3.2 HTTP body解析库

访问OSS的示例代码如下所示。

var gm = require('gm').subClass({ imageMagick: true });
exports.handler = function (event, context, callback) {
    gm(event)
        .flip()
        .toBuffer('PNG', function (err, buffer) {
            if (err) return callback(err);
            callback(null, buffer); 
       });
};
说明 上面的函数直接使用event作为图片的二进制数据,并且直接把生成的图片作为二进制数据返回。

使用自定义模块

如果您需要使用自定义模块,则需要将您的自定义模块与代码一起打包上传。您可以通过以下方式进行依赖管理。

注意 如果您是在本地打包自定义模块,需要上传node_modules。
  • 方法一:使用npm包管理器安装依赖。

    本文以安装MySQL数据库为例进行详细介绍。

    1. 执行以下命令建立一个目录,用于存放代码和依赖模块。
      mkdir /tmp/code
    2. 执行以下命令,进入代码目录。
      cd /tmp/code
    3. 执行以下命令安装依赖。
      npm install mysql
    4. 新建代码文件,例如/tmp/code/index.js,在代码中使用MySQL。
      var mysql = require('mysql');
      var connection;
      // exports.initializer: initializer function
      exports.initializer = function (context, callback) {
        connection = mysql.createConnection({
          host: 'localhost',
          user: '***',
          password: '*******',
          database: 'my_db'
        });
        connection.connect();
      }
      
      exports.handler = function (event, context, callback) {
        connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
          if (error) return callback(error);
          console.log('The solution is: ', results[0].solution);
          callback(null, results[0].solution);
        });
        connection.end();
      };
    5. 打包上传。

      打包时,需要针对文件进行打包,而不是针对代码整体目录进行打包。打包完成后,入口函数文件需要位于包内的根目录。

      • 在Windows下打包时,可以进入函数代码目录,全选所有文件以后,单击鼠标右键,选择压缩为ZIP包,生成代码包。
      • 在Linux下打包时,通过压缩命令,将源文件指定为代码目录下的所有文件,实现生成部署代码包,例如cd /tmp/code && zip -r code.zip*

      打包后,登录函数计算控制台,在目标函数的函数代码页签,在上传代码的下拉列表内选择通过 OSS 上传上传 zip 包方式上传代码包。

  • 方法二:使用Serverless Devs安装依赖。

    下文以安装MySQL库为例,介绍如何安装依赖。关于如何使用Serverless Devs安装依赖的更多信息,请参见多语言安装依赖示例

    1. 执行以下命令,初始化项目。
      s init devsapp/start-fc-event-nodejs12 -d start-fc-event-nodejs12

      -d用于指定项目名称,本示例指定的项目名称为start-fc-event-nodejs12。

      输出示例:
       Serverless Awesome: https://github.com/Serverless-Devs/package-awesome
      
       file decompression completed
       please select credential alias default
      
           ____  _     _ ___  _ _     _        _____ ____
          /  _ \/ \   / \\  \/// \ /\/ \  /|  /    //   _\
          | / \|| |   | | \  / | | ||| |\ ||  |  __\|  /
          | |-||| |_/\| | / /  | \_/|| | \||  | |   |  \__
          \_/ \|\____/\_//_/   \____/\_/  \|  \_/   \____/
      
      
      
          Welcome to the Aliyun FC start application
           This application requires to open these services:
               FC : https://fc.console.aliyun.com/
           This application can help you quickly deploy the aliyun fc project.
           The application uses FC component:
              * Help Docs  : https://github.com/devsapp/fc
              * Yaml Config: https://github.com/devsapp/fc/blob/main/docs/zh/yaml.md
           The application homepage: https://github.com/devsapp/start-fc
      
      
       Thanks for using Serverless-Devs
       You could [cd /test/start-fc-event-nodejs12] and enjoy your serverless journey!
       If you need help for this example, you can use [s -h] after you enter folder.
       Document Star:https://github.com/Serverless-Devs/Serverless-Devs
      
      ? Do you want to deploy the project immediately? No//选择不部署项目。
    2. 创建并编辑package.json文件。
      1. 执行以下命令,进入代码目录。
        cd start-fc-event-nodejs12/code
      2. 创建package.json文件。
        • macOS操作系统或Linux操作系统
          touch package.json
        • Windows操作系统
          echo >package.json
      3. 编辑package.json文件,该文件的内容如下:
        {
          "dependencies": {
            "mysql": "^2.18.1"
          }
        }
    3. 执行以下命令,安装依赖。
      1. 执行以下命令,进入项目目录。
        cd ..
      2. 执行以下命令,安装依赖。
        s build --use-docker
        输出示例:
        [2021-12-13 11:15:10] [INFO] [S-CLI] - Start ...
        [2021-12-13 11:15:10] [INFO] [FC-BUILD] - Build artifact start...
        [2021-12-13 11:15:10] [INFO] [FC-BUILD] - Use docker for building.
        [2021-12-13 11:15:11] [INFO] [FC-BUILD] - Build function using image: registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-nodejs12:build-1.9.21
        [2021-12-13 11:15:12] [INFO] [FC-BUILD] - begin pulling image registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-nodejs12:build-1.9.21, you can also use docker pull registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-nodejs12:build-1.9.21 to pull image by yourself.
        build-1.9.21: Pulling from aliyunfc/runtime-nodejs12
        ......
        Digest: sha256:bddd782a1a0f4a359d662ba896952bfb19e5f99c1fe6a73879ac05dab8101e08
        Status: Downloaded newer image for registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-nodejs12:build-1.9.21
        / builder begin to build
        builder begin to build, runtime is: nodejs12, sourceDir:  /code
        - builder begin to build
        running task: CopySource
        \ builder begin to build
        [2021-12-13 11:18:06] [INFO] [FC-BUILD] - Build artifact successfully.
        
        Tips for next step
        ======================
        * Invoke Event Function: s local invoke
        * Invoke Http Function: s local start
        * Deploy Resources: s deploy
        End of method: build
    4. 执行以下命令,部署项目。
      s deploy
      输出示例:
      [2021-12-03 08:02:11] [INFO] [S-CLI] - Start ...
      [2021-12-03 08:02:15] [INFO] [FC-DEPLOY] - Using region: cn-hangzhou
      [2021-12-03 08:02:15] [INFO] [FC-DEPLOY] - Using access alias: default
      [2021-12-03 08:02:15] [INFO] [FC-DEPLOY] - Using accessKeyID: LTAI4G4cwJkK4Rza6xd9****
      [2021-12-03 08:02:15] [INFO] [FC-DEPLOY] - Using accessKeySecret: eCc0GxSpzfq1DVspnqqd6nmYNN****
       Using fc deploy type: sdk, If you want to deploy with pulumi, you can [s cli fc-default set deploy-type pulumi] to switch.
      [2021-12-03 08:02:17] [INFO] [FC-DEPLOY] - Checking Service fc-deploy-service exists
      [2021-12-03 08:02:18] [INFO] [FC-DEPLOY] - Checking Function event-nodejs12 exists
      [2021-12-03 08:02:18] [INFO] [FC-DEPLOY] - Fc detects that you have run build command for function: event-nodejs12.
      [2021-12-03 08:02:18] [INFO] [FC-DEPLOY] - Using codeUri: /test/jy/start-fc-event-nodejs12/.s/build/artifacts/fc-deploy-service/event-nodejs12
      [2021-12-03 08:02:18] [INFO] [FC-DEPLOY] - Fc add/append some content to your origin environment variables for finding dependencies generated by build command.
      {
        "LD_LIBRARY_PATH": "/code/.s/root/usr/local/lib:/code/.s/root/usr/lib:/code/.s/root/usr/lib/x86_64-linux-gnu:/code/.s/root/usr/lib64:/code/.s/root/lib:/code/.s/root/lib/x86_64-linux-gnu:/code/.s/root/python/lib/python2.7/site-packages:/code/.s/root/python/lib/python3.6/site-packages:/code:/code/lib:/usr/local/lib",
        "PATH": "/code/.s/root/usr/local/bin:/code/.s/root/usr/local/sbin:/code/.s/root/usr/bin:/code/.s/root/usr/sbin:/code/.s/root/sbin:/code/.s/root/bin:/code:/code/node_modules/.bin:/code/.s/python/bin:/code/.s/node_modules/.bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/sbin:/bin",
        "NODE_PATH": "/code/node_modules:/usr/local/lib/node_modules",
        "PYTHONUSERBASE": "/code/.s/python"
      }
       Make service fc-deploy-service success.
       Make function fc-deploy-service/event-nodejs12 success.
      [2021-12-03 08:02:24] [INFO] [FC-DEPLOY] - Checking Service fc-deploy-service exists
      [2021-12-03 08:02:24] [INFO] [FC-DEPLOY] - Checking Function event-nodejs12 exists
      
      Tips for next step
      ======================
      * Display information of the deployed resource: s info
      * Display metrics: s metrics
      * Display logs: s logs
      * Invoke remote function: s invoke
      * Remove Service: s remove service
      * Remove Function: s remove function
      * Remove Trigger: s remove trigger
      * Remove CustomDomain: s remove domain
      
      
      
      fc-deploy-test:
        region:   cn-hangzhou
        service:
          name: fc-deploy-service
        function:
          name:       event-nodejs12
          runtime:    nodejs12
          handler:    index.handler
          memorySize: 128
          timeout:    60

    登录函数计算控制台,即可看到创建成功的服务、函数,且触发时可以返回函数的执行结果。

调用外部命令

您的函数可能会用到一些工具,而这些工具并不是用Node.js写的。例如,Shell、C++或者Go编译出来的可执行文件。您仍然可以将这些工具与代码一起打包,然后在函数中通过运行外部命令的方法来使用它们。以下代码演示了如何运行一个Shell脚本。

var exec = require('child_process');

exports.handler = function(event, context, callback) {
  var scriptPath = process.env['FC_FUNC_CODE_PATH'] + '/script.sh';
  exec.exec('bash '+scriptPath, {}, function(err, stdout, stderr) {
    if (err) return callback(err);
    console.log(stdout, stderr);
    callback(null, stdout);
  });
};
说明 使用C、C++、Go编译出来的可执行文件,需要与函数计算的运行环境兼容。函数计算的Node.js运行环境如下所示。
  • Linux内核版本:Linux 4.4.24-2.al7.x86_64。
  • Docker基础镜像:docker pull node:6.10。