請(qǐng)求處理程序(Handler)
您可以使用Node.js請(qǐng)求處理程序響應(yīng)接收到的事件并執(zhí)行相應(yīng)的業(yè)務(wù)邏輯。本文介紹Node.js請(qǐng)求處理程序的相關(guān)概念、結(jié)構(gòu)特點(diǎn)和示例。
什么是請(qǐng)求處理程序
FC函數(shù)的請(qǐng)求處理程序,是函數(shù)代碼中處理請(qǐng)求的方法。當(dāng)您的FC函數(shù)被調(diào)用時(shí),函數(shù)計(jì)算會(huì)運(yùn)行您提供的Handler方法處理請(qǐng)求。您可以通過函數(shù)計(jì)算控制臺(tái)的請(qǐng)求處理程序參數(shù)配置Handler。
對(duì)Node.js語言的FC函數(shù)而言,您的請(qǐng)求處理程序格式為文件名.方法名
。例如,您的文件名為index.js
或index.mjs
,方法名為handler
,則請(qǐng)求處理程序?yàn)?code data-tag="code" code-type="xCode" class="code">index.handler。
關(guān)于FC函數(shù)的具體定義和相關(guān)操作,請(qǐng)參見創(chuàng)建事件函數(shù)。
請(qǐng)求處理程序的具體配置均需符合函數(shù)計(jì)算平臺(tái)的配置規(guī)范。配置規(guī)范因請(qǐng)求處理程序類型而異。
Handler簽名
函數(shù)計(jì)算從Node.js 18運(yùn)行時(shí)開始支持ECMAScript(ES)模塊。在此之前(Node.js 16及以前的版本),函數(shù)計(jì)算僅支持使用CommonJS 模塊。詳情請(qǐng)參見將請(qǐng)求處理程序指定為ES模塊。
一個(gè)簡單的Event Handler簽名定義如下。
Node.js 18或Node.js 20
ES模塊
當(dāng)前示例代碼支持一鍵部署,您可以直接在函數(shù)計(jì)算FC中一鍵部署本代碼。start-fc3-nodejs-es
// index.mjs
export const handler = async (event, context) => {
console.log("receive event: \n" + event);
return "Hello World!";
};
CommonJS模塊
// index.js
exports.handler = async function(event, context) {
console.log("receive event: \n" + event);
return "Hello World!";
};
Node.js 16及以下版本
// index.js
exports.handler = async function(event, context, callback) {
console.log("event: \n" + event);
callback(null, 'hello world');
};
以上示例代碼解析如下:
handler
是方法名稱,與函數(shù)計(jì)算控制臺(tái)配置的請(qǐng)求處理程序相對(duì)應(yīng)。例如,創(chuàng)建函數(shù)時(shí)指定的請(qǐng)求處理程序為index.handler
,那么函數(shù)計(jì)算會(huì)去加載index.js
中定義的handler
函數(shù),并從這里開始執(zhí)行。
函數(shù)計(jì)算運(yùn)行時(shí)會(huì)將請(qǐng)求參數(shù)傳遞到請(qǐng)求處理程序中,第一個(gè)參數(shù)是event
對(duì)象,包含請(qǐng)求的有效負(fù)載信息,event
對(duì)象是Buffer類型,您可以將其轉(zhuǎn)換成所需要的對(duì)象類型。第二個(gè)參數(shù)是 context
對(duì)象,提供在調(diào)用時(shí)的運(yùn)行上下文信息。更多信息,請(qǐng)參見上下文。
使用Node.js 18及以上版本的運(yùn)行時(shí)環(huán)境時(shí),建議您使用Async/Await功能,而不是使用回調(diào)函數(shù)
callback
。函數(shù)計(jì)算會(huì)根據(jù)返回值的類型對(duì)返回結(jié)果做相應(yīng)轉(zhuǎn)換。
Buffer類型:不轉(zhuǎn)換,原樣返回。
Object類型:轉(zhuǎn)換為JSON格式后返回。
其他類型:轉(zhuǎn)換為字符串后返回。
Async/Await
使用Node.js 18及以上版本的運(yùn)行時(shí)環(huán)境時(shí),建議您使用Async/Await方式來實(shí)現(xiàn)。Async/Await是一種簡潔、易讀的Node.js異步代碼編寫方式,無需嵌套回調(diào)或鏈?zhǔn)秸{(diào)用。
如果您使用的Node.js 16及以下版本的運(yùn)行時(shí)環(huán)境,則必須顯式使用回調(diào)方法 callback
發(fā)送響應(yīng),否則會(huì)出現(xiàn)請(qǐng)求超時(shí)錯(cuò)誤。
Async/Await方式與回調(diào)函數(shù)callback
相比,有以下優(yōu)點(diǎn):
可讀性更好:Async/Await方式的代碼更加線性和同步,更易于理解和維護(hù)。它避免了回調(diào)函數(shù)嵌套過深的情況,使代碼結(jié)構(gòu)更清晰。
調(diào)試和錯(cuò)誤處理更簡單:可以使用try-catch塊更方便地捕獲和處理異步操作中的錯(cuò)誤,錯(cuò)誤堆棧更加清晰,可以更準(zhǔn)確地追蹤錯(cuò)誤發(fā)生的位置。
效率更高:回調(diào)函數(shù)通常需要在代碼的不同部分之間切換。Async/Await方式可以減少上下文切換的數(shù)量,從而提高代碼效率。
示例一:解析JSON格式參數(shù)
示例代碼
當(dāng)您傳入JSON格式參數(shù)時(shí),函數(shù)計(jì)算會(huì)透傳參數(shù)內(nèi)容,需要您在代碼中自行解析。下面是解析JSON格式事件的代碼示例。
ES模塊
此示例僅支持運(yùn)行在Node.js 18及以上版本的運(yùn)行時(shí)環(huán)境。
export const handler = async (event, context) => {
var eventObj = JSON.parse(event.toString());
return eventObj['key'];
};
CommonJS模塊
當(dāng)前示例代碼支持一鍵部署,您可以直接在函數(shù)計(jì)算FC中一鍵部署本代碼。start-fc3-nodejs-json
exports.handler = function(event, context, callback) {
var eventObj = JSON.parse(event.toString());
callback(null, eventObj['key']);
};
前提條件
已創(chuàng)建Node.js函數(shù),具體操作,請(qǐng)參見創(chuàng)建事件函數(shù)。如果您需要將代碼指定為ES模塊,創(chuàng)建函數(shù)時(shí),運(yùn)行環(huán)境需選擇Node.js 18或Node.js 20。
操作步驟
登錄函數(shù)計(jì)算控制臺(tái),在左側(cè)導(dǎo)航欄,單擊函數(shù)。
在頂部菜單欄,選擇地域,然后在函數(shù)頁面,單擊目標(biāo)函數(shù)。
在函數(shù)配置頁面,選擇代碼頁簽,在代碼編輯器中輸入上述示例代碼,然后單擊部署代碼。
說明上述示例代碼中函數(shù)的請(qǐng)求處理程序是
index.js
中的handler
方法。如果您的函數(shù)的請(qǐng)求處理程序配置不同,請(qǐng)獲取對(duì)應(yīng)的文件和方法進(jìn)行更新。在代碼頁簽,單擊測試函數(shù)右側(cè)的圖標(biāo),從下拉列表中選擇配置測試參數(shù),輸入以下示例測試參數(shù),然后單擊確定。
{ "key": "value" }
單擊測試函數(shù)。
函數(shù)執(zhí)行成功后,查看返回結(jié)果,您可以看到返回結(jié)果為
value
。
示例二:通過臨時(shí)密鑰安全讀寫OSS的資源
示例代碼
您可以使用函數(shù)計(jì)算為您提供的臨時(shí)密鑰訪問對(duì)象存儲(chǔ)OSS,代碼示例如下所示。
ES模塊
此示例僅支持運(yùn)行在Node.js 18及以上版本的運(yùn)行時(shí)環(huán)境。
// index.mjs
import OSSClient from 'ali-oss';
export const handler = async (event, context) => {
console.log(event.toString());
var ossClient = new OSSClient({
accessKeyId: context.credentials.accessKeyId,
accessKeySecret: context.credentials.accessKeySecret,
stsToken: context.credentials.securityToken,
region: 'oss-cn-shenzhen',
bucket: 'my-bucket',
});
try {
const uploadResult = await ossClient.put('myObj', Buffer.from('hello, fc', "utf-8"));
console.log('upload success, ', uploadResult);
return "put object"
} catch (error) {
throw error
}
};
代碼示例解析:
context.credentials
:從 context 參數(shù)中獲取臨時(shí)密鑰,避免在代碼中硬編碼密碼等敏感信息。myObj
:OSS對(duì)象名。Buffer.from('hello, fc', "utf-8")
: 上傳的對(duì)象內(nèi)容。return "put object"
:上傳成功正常返回 "put object"。throw err
:上傳失敗時(shí)拋出異常。
CommonJS模塊
當(dāng)前示例代碼支持一鍵部署,您可以直接在函數(shù)計(jì)算FC中一鍵部署本代碼。start-fc3-nodejs-oss
var OSSClient = require('ali-oss');
exports.handler = function (event, context, callback) {
console.log(event.toString());
var ossClient = new OSSClient({
accessKeyId: context.credentials.accessKeyId,
accessKeySecret: context.credentials.accessKeySecret,
stsToken: context.credentials.securityToken,
region: `oss-${context.region}`,
bucket: process.env.BUCKET_NAME,
});
ossClient.put('myObj', Buffer.from('hello, fc', "utf-8")).then(function (res) {
callback(null, 'put object');
}).catch(function (err) {
callback(err);
});
};
示例代碼解析如下:
context.credentials
:表示從context
參數(shù)中獲取臨時(shí)密鑰,避免在代碼中硬編碼密碼等敏感信息。myObj
:OSS對(duì)象名稱。Buffer.from('hello, fc', "utf-8")
:上傳的對(duì)象的內(nèi)容。callback(null, 'put object')
:上傳成功正常返回put object
。callback(err)
:上傳失敗時(shí)返回err
。
前提條件
為服務(wù)配置具有訪問對(duì)象存儲(chǔ)OSS的權(quán)限的角色。具體操作,請(qǐng)參見授予函數(shù)計(jì)算訪問其他云服務(wù)的權(quán)限。
創(chuàng)建運(yùn)行環(huán)境為Node.js的函數(shù)。具體操作,請(qǐng)參見創(chuàng)建事件函數(shù)。如果您需要將代碼指定為ES模塊,創(chuàng)建函數(shù)時(shí),運(yùn)行環(huán)境需選擇Node.js 18或Node.js 20。
操作步驟
登錄函數(shù)計(jì)算控制臺(tái),在左側(cè)導(dǎo)航欄,單擊函數(shù)。
在頂部菜單欄,選擇地域,然后在函數(shù)頁面,單擊目標(biāo)函數(shù)。
(可選)在目標(biāo)函數(shù)的函數(shù)詳情頁簽,選擇代碼頁簽,然后在下方的WebIDE界面,依次選擇
打開終端,執(zhí)行以下命令安裝ali-oss依賴。npm install ali-oss --save
安裝完成后,在WebIDE界面左側(cè)代碼目錄可以看到生成了
node_modules
文件夾,文件夾內(nèi)包含ali-oss
目錄以及其他依賴庫。在目標(biāo)函數(shù)的函數(shù)詳情頁簽,選擇代碼頁簽,在下方的代碼編輯器中輸入上述示例代碼,保存并單擊部署代碼。
說明上述示例代碼中函數(shù)的請(qǐng)求處理程序是
index.js
或index.mjs
文件中的handler
方法。如果您的函數(shù)的請(qǐng)求處理程序配置不同,請(qǐng)獲取對(duì)應(yīng)的文件和方法進(jìn)行更新。上述示例代碼中
region
和bucket
需按照實(shí)際情況填寫。
單擊測試函數(shù)。
函數(shù)執(zhí)行成功后,查看返回結(jié)果,您可以看到返回結(jié)果為
put object
。
示例三:調(diào)用外部命令
您的Node.js程序也可以創(chuàng)建fork
進(jìn)程,調(diào)用外部命令。例如,您可以使用child_process
模塊調(diào)用Linux的ls -l
命令,輸出當(dāng)前目錄下的文件列表。代碼示例如下所示。
ES模塊
此示例僅支持運(yùn)行在Node.js 18及以上版本的運(yùn)行時(shí)環(huán)境。
'use strict';
import { exec } from 'child_process';
import { promisify } from 'util';
const execPromisify = promisify(exec);
export const handler = async (event, context) => {
try {
const { stdout, stderr } = await execPromisify("ls -l");
console.log(`stdout: ${stdout}`);
if (stderr !== "") {
console.error(`stderr: ${stderr}`);
}
return stdout;
} catch (error) {
console.error(`exec error: ${error}`);
return error;
}
}
CommonJS模塊
當(dāng)前示例代碼支持一鍵部署,您可以直接在函數(shù)計(jì)算FC中一鍵部署本代碼。start-fc3-nodejs-exec
'use strict';
var exec = require('child_process').exec;
exports.handler = (event, context, callback) => {
console.log('start to execute a command');
exec("ls -l", function(error, stdout, stderr){
callback(null, stdout);
});
}
示例四:使用HTTP觸發(fā)器調(diào)用函數(shù)
示例代碼
使用HTTP觸發(fā)器提供的URL調(diào)用函數(shù),函數(shù)代碼示例如下。
如果HTTP觸發(fā)器的認(rèn)證方式為無需認(rèn)證,您可以直接使用Postman或Curl工具來調(diào)用函數(shù)。具體操作,請(qǐng)參見操作步驟。
如果HTTP觸發(fā)器的認(rèn)證方式為簽名認(rèn)證或JWT認(rèn)證,請(qǐng)使用簽名方式或JWT認(rèn)證方式來調(diào)用函數(shù)。具體操作,請(qǐng)參見認(rèn)證鑒權(quán)。
關(guān)于HTTP觸發(fā)調(diào)用的請(qǐng)求負(fù)載格式和響應(yīng)負(fù)載格式,請(qǐng)參見HTTP觸發(fā)器調(diào)用函數(shù)。
ES模塊
此示例僅支持運(yùn)行在Node.js 18及以上版本的運(yùn)行時(shí)環(huán)境。
'use strict';
export const handler = async (event, context) => {
const eventObj = JSON.parse(event);
console.log(`receive event: ${JSON.stringify(eventObj)}`);
let body = 'Hello World!';
// get http request body
if ("body" in eventObj) {
body = eventObj.body;
if (eventObj.isBase64Encoded) {
body = Buffer.from(body, 'base64').toString('utf-8');
}
}
console.log(`receive http body: ${body}`);
return {
'statusCode': 200,
'body': body
};
}
CommonJS模塊
當(dāng)前示例代碼支持一鍵部署,您可以直接在函數(shù)計(jì)算FC中一鍵部署本代碼。start-fc3-nodejs-http
'use strict';
exports.handler = (event, context, callback) => {
const eventObj = JSON.parse(event);
console.log(`receive event: ${JSON.stringify(eventObj)}`);
let body = 'Hello World!';
// get http request body
if ("body" in eventObj) {
body = eventObj.body;
if (eventObj.isBase64Encoded) {
body = Buffer.from(body, 'base64').toString('utf-8');
}
}
console.log(`receive http body: ${body}`);
callback(null, {
'statusCode': 200,
'body': body
});
}
前提條件
已使用上述示例創(chuàng)建運(yùn)行環(huán)境為Node.js的函數(shù)并創(chuàng)建HTTP觸發(fā)器。具體操作,請(qǐng)參見創(chuàng)建事件函數(shù)和配置HTTP觸發(fā)器并使用HTTP觸發(fā)。如果您需要將代碼指定為ES模塊,創(chuàng)建函數(shù)時(shí),運(yùn)行環(huán)境需選擇Node.js 18或Node.js 20。
操作步驟
登錄函數(shù)計(jì)算控制臺(tái),在左側(cè)導(dǎo)航欄,單擊函數(shù)。
在頂部菜單欄,選擇地域,然后在函數(shù)頁面,單擊目標(biāo)函數(shù)。
在函數(shù)詳情頁面,單擊配置頁簽,然后再左側(cè)導(dǎo)航欄,單擊觸發(fā)器,在觸發(fā)器頁面獲取HTTP觸發(fā)器的公網(wǎng)訪問地址。
在Curl工具執(zhí)行以下命令,調(diào)用函數(shù)。
curl -i "https://test-nodejs-dlgxxr****.cn-shanghai.fcapp.run" -d 'Hello World!'
以上命令中,
https://test-nodejs-dlgxxr****.cn-shanghai.fcapp.run
為獲取到的HTTP觸發(fā)器公網(wǎng)訪問地址。響應(yīng)結(jié)果如下。
HTTP/1.1 200 OK Access-Control-Expose-Headers: Date,x-fc-request-id Content-Disposition: attachment Content-Length: 12 Content-Type: text/html; charset=utf-8 Etag: W/"c-Lve95gjOVATpfV8EL5X4nxwjKHE" X-Fc-Request-Id: 1-65d866a8-15d8796a-cb9b4feb69ca X-Powered-By: Express Date: Fri, 23 Feb 2024 09:34:34 GMT Hello World!curl: (3) URL using bad/illegal format or missing URL
示例五:使用HTTP觸發(fā)器下載文件
示例代碼
如果您想通過代碼返回一個(gè)圖片、壓縮包或二進(jìn)制文件,可以使用HTTP觸發(fā)器實(shí)現(xiàn)在函數(shù)代碼中返回,函數(shù)代碼示例如下。
ES模塊
此示例僅支持運(yùn)行在Node.js 18及以上版本的運(yùn)行時(shí)環(huán)境。
// index.mjs
'use strict';
import mime from 'mime';
import fs from 'fs/promises';
import path from 'path';
export const handler = async (event, context) => {
const fileContent = 'This is a sample text file created in the code.';
const fileName = 'sample.txt';
const filePath = path.join('/tmp', fileName);
try {
await fs.writeFile(filePath, fileContent);
const mimeType = mime.getType(filePath);
if (!mimeType) {
throw new Error('Unable to determine MIME type');
}
const fileData = await fs.readFile(filePath);
const fileBase64 = Buffer.from(fileData).toString('base64');
const fcResponse = {
'statusCode': 200,
'headers': {
'Content-Type': mimeType,
'Content-Disposition': `attachment; filename="${fileName}"`,
},
'body': fileBase64,
'isBase64Encoded': true
};
console.log('File generated and fetched successfully.');
return fcResponse;
} catch (err) {
console.error(err);
return {
'statusCode': 500,
'body': err.message
};
}
};
CommonJS模塊
// index.js
'use strict';
const mime = require('mime');
const fs = require('fs');
const path = require('path');
exports.handler = async (event, context, callback) => {
const fileContent = 'This is a sample text file created in the code.';
const fileName = 'sample.txt';
const filePath = path.join('/tmp', fileName);
try {
fs.writeFileSync(filePath, fileContent);
const mimeType = mime.getType(filePath);
if (!mimeType) {
throw new Error('Unable to determine MIME type');
}
const fileData = fs.readFileSync(filePath);
const fileBase64 = Buffer.from(fileData).toString('base64');
const fcResponse = {
'statusCode': 200,
'headers': {
'Content-Type': mimeType,
'Content-Disposition': `attachment; filename="${fileName}"`,
},
'body': fileBase64,
'isBase64Encoded': true
};
console.log('File generated and fetched successfully.');
callback(null, fcResponse);
} catch (err) {
console.error(err);
callback(null, {
'statusCode': 500,
'body': err.message
});
}
};
前提條件
已使用上述示例創(chuàng)建運(yùn)行環(huán)境為Node.js的函數(shù)并創(chuàng)建HTTP觸發(fā)器。具體操作,請(qǐng)參見創(chuàng)建事件函數(shù)和配置HTTP觸發(fā)器并使用HTTP觸發(fā)。如果您需要將代碼指定為ES模塊,創(chuàng)建函數(shù)時(shí),運(yùn)行環(huán)境需選擇Node.js 18或Node.js 20。
操作步驟
登錄函數(shù)計(jì)算控制臺(tái),在左側(cè)導(dǎo)航欄,單擊函數(shù)。
在頂部菜單欄,選擇地域,然后在函數(shù)頁面,單擊目標(biāo)函數(shù)。
在函數(shù)詳情頁面,選擇代碼頁簽,然后選擇
打開終端窗口,執(zhí)行命令npm install mime@2
安裝mime庫。安裝完成后,單擊部署代碼。在函數(shù)配置頁面的觸發(fā)器頁簽,獲取HTTP觸發(fā)器的公網(wǎng)訪問地址,復(fù)制URL到瀏覽器并回車。
回車后觸發(fā)器函數(shù)執(zhí)行,執(zhí)行成功后下載文件到本地。