函数计算目前支持Node.js 6.10(runtime=nodejs6)、Node.js 8.9.0(runtime=nodejs8)、Node.js 10.15.3(runtime=nodejs10)和Node.js 12.16.1(runtime=nodejs12)运行环境。本文介绍了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-323ad89118e5 [INFO] hello world
日志级别 | 对应接口 |
---|---|
error | console.error |
warn | console.warn |
info | console.info |
verbose | console.log |
debug | console.debug |
执行以下代码,打印WARN、ERROR级别的日志。
'use strict';
exports.handler = function(evt, ctx, cb) {
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");
cb(null, evt);
};
输出的日志内容如下。
message:2017-07-05T05:13:35.920Z a72df088-f738-cee3-e0fe-323ad89118e5 [ERROR] console error 1
message:2017-07-05T05:13:35.920Z a72df088-f738-cee3-e0fe-323ad89118e5 [ERROR] console error 2
message:2017-07-05T05:13:35.920Z a72df088-f738-cee3-e0fe-323ad89118e5 [WARN] console warn 2
返回信息
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 3 seconds"}
错误处理
对于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 | 视觉算法库 |
https://help.aliyun.com/document_detail/body | 5.1.0 | HTTP https://help.aliyun.com/document_detail/body解析库 |
raw-https://help.aliyun.com/document_detail/body | 2.3.2 | HTTP https://help.aliyun.com/document_detail/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);
});
};
使用自定义模块
如果您需要使用自定义模块,则需要将您的自定义模块与代码一起打包上传。您可以通过以下方式进行依赖管理。
- 方法一:使用npm包管理器进行依赖管理。
本文以安装MySQL数据库为例进行详细介绍。
- 执行以下命令建立一个目录,用于存放代码和依赖模块。
mkdir /tmp/code
- 执行以下命令在/tmp/code目录下安装依赖。
cd /tmp/code npm install mysql
- 新建代码文件,例如/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(); };
- 打包上传。
打包时,需要针对文件进行打包,而不是针对代码整体目录进行打包。打包完成后,入口函数文件需要位于包内的根目录。
- 在Windows下打包时,可以进入函数代码目录,全选所有文件以后,单击鼠标右键,选择压缩为zip包,生成代码包。
- 在Linux下打包时,通过调用zip命令时,将源文件指定为代码目录下的所有文件,实现生成部署代码包,例如
zip code.zip /home/code/*
。
打包后,在函数计算控制台指定函数中的代码执行页面,您可以选择OSS上传或者代码包上传方式上传代码包。
- 执行以下命令建立一个目录,用于存放代码和依赖模块。
- 方法二:使用
fun install
安装依赖。如果您使用Funcraft部署应用,可以使用
fun install
命令来安装依赖。更多信息,请参见使用fun install安装第三方依赖。本文以安装mysql库为例进行详细介绍。- 执行以下命令在函数根目录下初始化Funfile文件。
fun install init ? Select a runtime nodejs6 ? nodejs8 nodejs10 nodejs12 python2.7 python3 java8 php7.2 (Move up and down to reveal more choices)
- 选择语言nodejs8,在当前目录生成一个名为Funfile的文件,编辑文件内容。
RUNTIME nodejs8 RUN npm install mysql
- 新建template.yml文件。更多信息,请参见template.yml。例如
/tmp/code/template.yml
,示例如下。ROSTemplateFormatVersion: '2015-09-01' Transform: 'Aliyun::Serverless-2018-04-03' Resources: FunDemo: Type: 'Aliyun::Serverless::Service' nodejsdemo: Type: 'Aliyun::Serverless::Function' Properties: Handler: index.handler Runtime: nodejs8 Initializer: index.initializer CodeUri: './'
该template.yml文件含义如下:声明名为FunDemo的服务,在这个服务下,声明一个名为nodejsdemo的函数,配置函数入口为
index.handler
,Initializer为index.initializer
函数的runtime为nodejs8。并指定CodeUri为当前目录。更多信息,请参见CodeUri。在部署时,Funcraft会将CodeUri指定目录下的内容打包上传。更多的配置规则,请参见Serverless Application Model。
- 在函数根目录下执行
fun install
命令安装依赖。fun install
返回结果如下。
using template: template.yml start installing function dependencies without docker building FunDemo/nodejsdemo Funfile exist, Fun will use container to build forcely Step 1/2 : FROM registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-nodejs8:build-1.9.4 ---> 8c6c75614064 Step 2/2 : RUN npm install mysql ---> Using cache ---> 715f4427faf9 sha256:715f4427faf9b66238328e44736078f2ac4bbc0d403e441a6c460b6cc2f405ae Successfully built 715f4427faf9 Successfully tagged fun-cache-58fa61db-dd07-416b-aa47-a6ee752ec6d7:latest copying function artifact to /Users/txd123/Desktop/express Install Success Tips for next step ====================== * Invoke Event Function: fun local invoke * Invoke Http Function: fun local start * Build Http Function: fun build * Deploy Resources: fun deploy
- 使用Funcraft工具部署。
fun deploy
返回结果如下。
using region: cn-hangzhou using accountId: ***********3557 using accessKeyId: ***********r3Ra using timeout: 300 Waiting for service FunDemo to be deployed... Waiting for function nodejsdemo to be deployed... Waiting for packaging function nodejs code... package function nodejs code done function nodejsdemo deploy success service FunDemo deploy success
登录函数计算控制台,即可看到相关的服务、函数被创建成功,且触发执行可以返回正确的结果。
- 执行以下命令在函数根目录下初始化Funfile文件。
调用外部命令
您的函数可能会用到一些工具,而这些工具并不是用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);
});
};
- Linux内核版本:Linux 4.4.24-2.al7.x86_64。
- Docker基础镜像:docker pull node:6.10。