.
├── func.yaml (1)
├── index.js (2)
├── package.json (3)
├── README.md
└── test (4)
├── integration.js
└── unit.js
创建 Node.js 函数项目后,您可以修改提供的模板文件,以向函数添加业务逻辑。这包括配置函数调用以及返回的头信息和状态码。
在开发函数之前,必须完成配置 OpenShift Serverless 函数中的步骤。
使用 Knative (kn
) CLI 创建 Node.js 函数时,项目目录看起来像一个典型的 Node.js 项目。唯一的例外是附加的 func.yaml
文件,该文件用于配置函数。
http
和 event
触发器函数具有相同的模板结构
.
├── func.yaml (1)
├── index.js (2)
├── package.json (3)
├── README.md
└── test (4)
├── integration.js
└── unit.js
1 | func.yaml 配置文件用于确定镜像名称和注册表。 |
2 | 您的项目必须包含一个导出单个函数的 index.js 文件。 |
3 | 您不限于模板 package.json 文件中提供的依赖项。您可以像在任何其他 Node.js 项目中一样添加其他依赖项。添加 npm 依赖项的示例
为部署构建项目时,这些依赖项将包含在创建的运行时容器镜像中。 |
4 | 集成和单元测试脚本作为函数模板的一部分提供。 |
使用 Knative (kn
) CLI 创建函数项目时,您可以生成一个响应 CloudEvents 的项目,或者一个响应简单 HTTP 请求的项目。Knative 中的 CloudEvents 作为 POST 请求通过 HTTP 传输,因此两种函数类型都侦听并响应传入的 HTTP 事件。
Node.js 函数可以使用简单的 HTTP 请求调用。收到传入请求时,将使用 context
对象作为第一个参数调用函数。
通过提供 context
对象作为第一个参数来调用函数。此对象提供对传入 HTTP 请求信息的访问。
此信息包括 HTTP 请求方法、与请求一起发送的任何查询字符串或头信息、HTTP 版本和请求主体。包含 CloudEvent
的传入请求会将传入的 CloudEvent 实例附加到上下文对象,以便可以通过使用 context.cloudevent
来访问它。
context
对象有一个单一方法 cloudEventResponse()
,它接受数据值并返回 CloudEvent。
在 Knative 系统中,如果作为服务部署的函数由发送 CloudEvent 的事件代理调用,则代理会检查响应。如果响应是 CloudEvent,则此事件将由代理处理。
// Expects to receive a CloudEvent with customer data
function handle(context, customer) {
// process the customer
const processed = handle(customer);
return context.cloudEventResponse(customer)
.source('/handle')
.type('fn.process.customer')
.response();
}
如果传入请求是 CloudEvent,则会从事件中提取与 CloudEvent 关联的任何数据,并作为第二个参数提供。例如,如果收到一个 CloudEvent,其 data 属性中包含类似于以下内容的 JSON 字符串
{
"customerId": "0123456",
"productId": "6543210"
}
调用时,函数的第二个参数(在 context
对象之后)将是一个 JavaScript 对象,它具有 customerId
和 productId
属性。
function handle(context, data)
此示例中的 data
参数是一个 JavaScript 对象,包含 customerId
和 productId
属性。
函数可以接收任何数据,而不仅仅是 CloudEvents
。例如,您可能希望使用 POST 方法并使用主体中的任意对象来调用函数
{
"id": "12345",
"contact": {
"title": "Mr.",
"firstname": "John",
"lastname": "Smith"
}
}
在这种情况下,您可以按如下方式定义函数:
function handle(context, customer) {
return "Hello " + customer.contact.title + " " + customer.contact.lastname;
}
向函数提供 contact 对象将返回以下输出:
Hello Mr. Smith
CloudEvents 可以包含各种数据类型,包括 JSON、XML、纯文本和二进制数据。这些数据类型将以各自的格式提供给函数。
JSON 数据:作为 JavaScript 对象提供。
XML 数据:作为 XML 文档提供。
纯文本:作为字符串提供。
二进制数据:作为 Buffer 对象提供。
通过检查 Content-Type 标头并相应地解析数据,确保您的函数可以处理不同的数据类型。例如:
function handle(context, data) {
if (context.headers['content-type'] === 'application/json') {
// handle JSON data
} else if (context.headers['content-type'] === 'application/xml') {
// handle XML data
} else {
// handle other data types
}
}
函数可以返回任何有效的 JavaScript 类型,也可以没有返回值。当函数没有指定返回值并且没有指示错误时,调用者将收到 204 No Content
响应。
函数也可以返回 CloudEvent 或 Message
对象,以便将事件推送到 Knative Eventing 系统。在这种情况下,开发人员不需要理解或实现 CloudEvent 消息传递规范。从返回值中提取标头和其他相关信息,并随响应一起发送。
function handle(context, customer) {
// process customer and return a new CloudEvent
return new CloudEvent({
source: 'customer.processor',
type: 'customer.processed'
})
}
函数可以返回任何有效的 JavaScript 类型,包括字符串、数字和布尔值等基本类型。
function handle(context) {
return "This function Works!"
}
调用此函数将返回以下字符串:
$ curl https://myfunction.example.com
This function Works!
function handle(context) {
let somenumber = 100
return { body: somenumber }
}
调用此函数将返回以下数字:
$ curl https://myfunction.example.com
100
function handle(context) {
let someboolean = false
return { body: someboolean }
}
调用此函数将返回以下布尔值:
$ curl https://myfunction.example.com
false
直接返回基本类型而不用对象包装它们会导致返回 204 No Content
状态码以及空主体。
function handle(context) {
let someboolean = false
return someboolean
}
调用此函数将返回以下内容:
$ http :8080
HTTP/1.1 204 No Content
Connection: keep-alive
...
您可以通过向 return
对象添加 headers
属性来设置响应标头。这些标头将被提取并与响应一起发送给调用者。
function handle(context, customer) {
// process customer and return custom headers
// the response will be '204 No content'
return { headers: { customerid: customer.id } };
}
您可以通过向 return
对象添加 statusCode
属性来设置返回给调用者的状态码。
function handle(context, customer) {
// process customer
if (customer.restricted) {
return { statusCode: 451 }
}
}
也可以为函数创建和抛出的错误设置状态码。
function handle(context, customer) {
// process customer
if (customer.restricted) {
const err = new Error(‘Unavailable for legal reasons’);
err.statusCode = 451;
throw err;
}
}
可以在您的计算机上本地测试 Node.js 函数。使用 kn func create
创建函数时创建的默认项目中,有一个包含一些简单的单元和集成测试的 **test** 文件夹。
集群上已安装 OpenShift Serverless Operator 和 Knative Serving。
您已安装 Knative (kn
) CLI。
您已使用 kn func create
创建了一个函数。
导航到函数的 **test** 文件夹。
运行测试:
$ npm test
您可以覆盖 Node.js 函数的 liveness
和 readiness
探针值。这允许您配置对函数执行的健康检查。
集群上已安装 OpenShift Serverless Operator 和 Knative Serving。
您已安装 Knative (kn
) CLI。
您已使用 kn func create
创建了一个函数。
在您的函数代码中,创建 Function
对象,该对象实现以下接口:
export interface Function {
init?: () => any; (1)
shutdown?: () => any; (2)
liveness?: HealthCheck; (3)
readiness?: HealthCheck; (4)
logLevel?: LogLevel;
handle: CloudEventFunction | HTTPFunction; (5)
}
1 | 初始化函数,在服务器启动之前调用。此函数是可选的,应为同步函数。 |
2 | 关闭函数,在服务器停止后调用。此函数是可选的,应为同步函数。 |
3 | 存活性函数,用于检查服务器是否存活。此函数是可选的,如果服务器存活,则应返回 200/OK。 |
4 | 就绪性函数,用于检查服务器是否已准备好接受请求。此函数是可选的,如果服务器已准备好,则应返回 200/OK。 |
5 | 用于处理 HTTP 请求的函数。 |
例如,将以下代码添加到 index.js
文件:
const Function = {
handle: (context, body) => {
// The function logic goes here
return 'function called'
},
liveness: () => {
process.stdout.write('In liveness\n');
return 'ok, alive';
}, (1)
readiness: () => {
process.stdout.write('In readiness\n');
return 'ok, ready';
} (2)
};
Function.liveness.path = '/alive'; (3)
Function.readiness.path = '/ready'; (4)
module.exports = Function;
1 | 自定义 liveness 函数。 |
2 | 自定义 readiness 函数。 |
3 | 自定义 liveness 端点。 |
4 | 自定义 readiness 端点。 |
作为 Function.liveness.path
和 Function.readiness.path
的替代方法,您可以使用 LIVENESS_URL
和 READINESS_URL
环境变量指定自定义端点。
run:
envs:
- name: LIVENESS_URL
value: /alive (1)
- name: READINESS_URL
value: /ready (2)
1 | 存活性路径,此处设置为 /alive 。 |
2 | 就绪性路径,此处设置为 /ready 。 |
将新的端点添加到 func.yaml
文件中,以便它们正确绑定到 Knative 服务的容器。
deploy:
healthEndpoints:
liveness: /alive
readiness: /ready
context
对象具有函数开发人员可以访问的多个属性。访问这些属性可以提供有关 HTTP 请求的信息并将输出写入集群日志。
提供一个日志记录对象,可用于将输出写入集群日志。该日志符合 Pino 日志记录 API。
function handle(context) {
context.log.info(“Processing customer”);
}
您可以使用 kn func invoke
命令访问该函数。
$ kn func invoke --target 'http://example.function.com'
{"level":30,"time":1604511655265,"pid":3430203,"hostname":"localhost.localdomain","reqId":1,"msg":"Processing customer"}
您可以将日志级别更改为 fatal
、error
、warn
、info
、debug
、trace
或 silent
之一。为此,请通过将这些值之一分配给使用 config
命令的环境变量 FUNC_LOG_LEVEL
来更改 logLevel
的值。
返回请求的查询字符串(如果有),作为键值对。这些属性也位于上下文对象本身。
function handle(context) {
// Log the 'name' query parameter
context.log.info(context.query.name);
// Query parameters are also attached to the context
context.log.info(context.name);
}
您可以使用 kn func invoke
命令访问该函数。
$ kn func invoke --target 'http://example.com?name=tiger'
{"level":30,"time":1604511655265,"pid":3430203,"hostname":"localhost.localdomain","reqId":1,"msg":"tiger"}
返回请求主体(如果有)。如果请求主体包含 JSON 代码,则将对其进行解析,以便可以直接使用这些属性。
function handle(context) {
// log the incoming request body's 'hello' parameter
context.log.info(context.body.hello);
}
您可以使用 curl
命令调用该函数来访问它。
$ kn func invoke -d '{"Hello": "world"}'
{"level":30,"time":1604511655265,"pid":3430203,"hostname":"localhost.localdomain","reqId":1,"msg":"world"}
返回 HTTP 请求头作为对象。
function handle(context) {
context.log.info(context.headers["custom-header"]);
}
您可以使用 kn func invoke
命令访问该函数。
$ kn func invoke --target 'http://example.function.com'
{"level":30,"time":1604511655265,"pid":3430203,"hostname":"localhost.localdomain","reqId":1,"msg":"some-value"}