通用螺旋
通用运行时间的无服务器适配器 .
状态
安装
$ npm install @adobe/helix-universal
部署
通用螺旋 属于 螺旋部署 生态系统. 螺旋部署 是提供跨多个无服务器平台通用功能的部署能力的母项目.
支持的平台
Helix 部署可以部署通用职能:
- AWS 兰布达 - 传统的无服务器功能
- 谷歌云函数 - 谷歌云平台上的无服务器功能
- Apache 打开信箱 - 无服务器的开源平台
边距计算支持
螺旋部署插件边缘 将Helix Universal的覆盖范围扩展至边缘计算运行时间,允许部署到:
- 快速计算@ Edge - 边缘计算平台
- 云花岗工人 - 边缘计算平台
这使得您可以写出可以在边缘运行,更接近用户的通用函数,同时保持相同的通用函数界面.
秘密命名公约
在与Helix 部署一起部署时,秘密遵循一个命名公约,其中包括: helix-deploy 前缀 :
- AWS 保密管理器数字 :
/helix-deploy/{package-name}/all - 谷歌秘密管理器数字 :
projects/{project-id}/secrets/helix-deploy--{package-name}/versions/latest
该公约确保所有平台上部署的职能都能够妥善安排和获取秘密.
API 文档
这个库提供适配器,允许您写入跨多平台(AWS Lambda,Google Cloud函数和Apache OpenWhisk)的通用服务器无功能. 您的函数收到一个标准化 Request 对象和 Context 对象,无论基础平台.
通用函数签名
所有通用功能都遵循此签名:
async function main(request, context) {
// Your function logic here
return new Response('Hello, World!', {
status: 200,
headers: {
'content-type': 'text/plain',
},
});
}
参数:
request(请求):标准 获取 API 请求 包含 HTTP 请求细节的对象context(大学背景): 提供运行时间信息、函数元数据和公用事业的上下文对象
回返情况: A 类 获取 API 响应 对象
普遍背景
这个 context object提供一个标准化的接口,用于访问特定平台的信息和公用事业。 此外,插件和包装器可能会以额外的属性来扩展上下文(见 可用的插件包 页:1.
context.resolver
A 类 Resolver 例如,创建URL以引用其他函数/动作。 支持通过 x-ow-version-lock 头曰.
方法:
createURL(options): 创建用于引用其他函数的 URLoptions.name(字符串,需要):函数/动作名options.package(弦,可选): 软件包名称options.version(字符串,可选):要引用的版本
示例
// Invoke another function
const url = context.resolver.createURL({
package: 'helix-services',
name: 'content-proxy',
version: '1.2.3',
});
// url is a URL object pointing to the function
context.pathInfo
当前请求的路径信息 .
属性 :
suffix(字符串):请求路径后缀(例如,/foo/bar从/api/function/foo/bar(中文(简体) )
context.runtime
运行时环境信息.
属性 :
name(字符串):运行时名称('aws-lambda', (中文(简体) ),'googlecloud-functions',或'apache-openwhisk'(中文(简体) )region部署地区(例如:,'us-east-1', (中文(简体) ),'us-central1'(中文(简体) )accountId(字符串,只有AWS):AWS账户 ID
context.func
关于当前函数的信息 .
属性 :
name(字符串):函数名(没有软件包/版本的定名)package(字符串):软件包名称version(字符串):函数版本app(字符串):应用程序/名称空间名称fqn(字符串):完全限定名称(平台专用格式)
示例值:
{
name: 'dispatch',
package: 'helix-services',
version: '4.3.1',
app: 'helix-pages',
fqn: 'arn:aws:lambda:us-east-1:118435662149:function:helix-services--dispatch:4_3_1'
}
context.invocation
关于目前援引的资料.
属性 :
id(字符串):唯一引用ID(OpenWhisk的激活ID,AWS/Google的请求ID)deadline(数字):函数超时时的去除时间戳(毫秒)transactionId(弦,可选): 用于多次追踪的交易IDrequestId(弦,可选): 请求识别 HTTP 请求的IDevent(对象,只有AWS): Raw AWS Lambda 事件对象
context.env
环境变量对象. 这包括:
- 全体
process.env变量 - 从平台特定秘密管理器中装入的秘密( 当使用秘密插件时)
- 特定功能环境变量
说明: 以下环境变量被自动设定 :
HELIX_UNIVERSAL_RUNTIME: 运行时名称HELIX_UNIVERSAL_NAME函数名称HELIX_UNIVERSAL_PACKAGE软件包名称HELIX_UNIVERSAL_APP: 应用程序名称HELIX_UNIVERSAL_VERSION函数版本
context.log
符合 螺旋标记. 提供下列方法:
log(...args)fatal(...args)error(...args)warn(...args)info(...args)debug(...args)verbose(...args)silly(...args)trace(...args)
示例
context.log.info('Processing request', { url: request.url });
context.log.error('Something went wrong', error);
context.storage
用于生成云存储预签名的 URL 的存储 API .
方法:
presignURL(bucket, path, blobParams, method, expires): 生成一个预先签名的 URLbucket(字符串):存储桶名path(字符串):桶内的对象路径blobParams(对象,可选):附加参数(例如:,ContentType, (中文(简体) ),ContentDisposition(中文(简体) )method(字符串,可选):HTTP方法('GET'或者说'PUT'),默认为'GET'expires(数目,可选): 以秒计的过期时间,默认为60
示例
const url = await context.storage.presignURL(
'my-bucket',
'path/to/file.jpg',
{ ContentType: 'image/jpeg' },
'GET',
3600
);
context.attributes
一个用于存储用户定义属性的对象 。 这尤其有助于数据在 包装 和中间软件功能。 包装器可以存储计算值或初始化资源 context.attributes 因此,它们可以在请求的生命周期内被再利用,而无需重新初始化.
常用案例 :
- 缓存初始化资源(例如存储客户端、数据库连接)
- 在中间软件层之间传递数据
- 存储请求范围元数据
示例
// In a wrapper function
function storageWrapper(fn) {
return async (request, context) => {
// Initialize storage once and cache it in attributes
if (!context.attributes.storage) {
context.attributes.storage = new HelixStorage({
// ... configuration
});
}
return fn(request, context);
};
}
// In your main function
export async function main(request, context) {
// Access the cached storage instance
const storage = context.attributes.storage;
const bucket = storage.contentBus();
// Use other attributes
context.attributes.userId = '12345';
context.attributes.requestStartTime = Date.now();
return new Response('OK');
}
说明: 这个 context.attributes 对象被类似软件包大量使用 @adobe/helix-shared-storage 财务报告和审定财务报表 helix-admin 以缓存资源并在中间软件层之间共享数据.
自定义适配器
您可以使用 createAdapter 函数 :
import { createAdapter } from '@adobe/helix-universal/aws';
const adapter = createAdapter({
factory: async () => {
// Custom factory function to load your main function
return (await import('./my-main.js')).main;
},
});
export const handler = adapter;
插件
适配器支持用于扩展功能的插件系统:
机密插件
机密插件会自动从平台特定机密管理器中加载机密并注入其中 process.env 作为环境变量。 两个插件都是 默认包含 在他们各自的适配器中,所以每次引用时都会自动载入秘密.
秘密如何运作 :
- 秘密作为JSON对象存储在平台的秘密管理器中
- JSON 中的每个密钥值对都成为环境变量
- 只有已经不存在的秘密
process.env设定( 现有变量优先) - 机密可以输入
context.env财务报告和审定财务报表process.env在您的职责范围内
AWS 保密插件
AWS 机密插件从 AWS 机密管理器装入机密.
秘密命名公约:
- 秘密身份识别格式 :
/helix-deploy/{package-name}/all - 软件包名称取自 Lambda 函数名( 之前的所有
--(中文(简体) ) - 示例:用于函数
helix-services--dispatch,隐藏从/helix-deploy/helix-services/all
配置 :
import { lambda, awsSecretsPlugin } from '@adobe/helix-universal';
// Already included in default lambda export, but you can customize:
const customLambda = lambda.raw.with(awsSecretsPlugin, {
expiration: 3600000, // Cache expiration time in milliseconds (default: 1 hour)
checkDelay: 60000, // Modification check delay in milliseconds (default: 1 minute)
emulateEnv: { // For testing: provide mock secrets instead of calling AWS
API_KEY: 'test-key',
DB_PASSWORD: 'test-password',
},
});
缓冲行为 :
- 秘诀被缓存到内存中用于性能
- 缓存过期于
expiration时间( 默认:1小时) - 每个
checkDelay(默认:1分钟),插件检查密钥是否被修改 - 如果修改了密件, 则自动重新装入
- 这平衡了性能与不重新部署更新秘密的能力
AWS 全权证书: 插件需要 AWS 证书,通常通过:
- 附属于Lambda函数的IAM角色(被推荐)
- 环境变量:
AWS_ACCESS_KEY_ID, (中文(简体) ),AWS_SECRET_ACCESS_KEY, (中文(简体) ),AWS_SESSION_TOKEN - AWS 区域 :
AWS_REGION(对Lambda地区的违约)
处理错误 :
ResourceNotFoundException: 返回空对象{},允许该功能在没有秘密的情况下继续ThrottlingException: 丢出错误statusCode: 429- 其他错误: 丢出一个错误, 它会被适配器的错误处理器捕获
自定义终点( 用于本地测试) :
// Use localstack or other AWS-compatible endpoint
process.env.AWS_ENDPOINT_URL = 'http://localhost:4566';
示例秘密结构:
在 AWS 保密管理器中存储此 JSON /helix-deploy/my-package/all数字 :
{
"API_KEY": "your-api-key-here",
"DATABASE_URL": "postgresql://...",
"JWT_SECRET": "your-jwt-secret"
}
谷歌机密插件
Google秘密插件从Google秘密管理员处装入秘密.
秘密命名公约:
- 秘密路径格式 :
projects/{project-id}/secrets/helix-deploy--{package-name}/versions/latest - 工程ID 从 Cloud 函数主机名子域中提取
- 软件包名称取自
K_SERVICE环境变量( 前所有--(中文(简体) ) - 包名中的点被下划线所取代
- 示例:用于函数
helix-services--dispatch在项目中helix-225321,隐藏从projects/helix-225321/secrets/helix-deploy--helix_services/versions/latest
配置 :
import { google, googleSecretsPlugin } from '@adobe/helix-universal';
// Already included in default google export, but you can customize:
const customGoogle = google.raw.with(googleSecretsPlugin, {
emulateEnv: { // For testing: provide mock secrets instead of calling Google
API_KEY: 'test-key',
DB_PASSWORD: 'test-password',
},
});
缓冲行为 :
- 没有缓冲:每次引用时,都会获取秘密
- 这保证你总是有最新的秘密, 但可能影响性能
谷歌云地证: 该插件需要Google Cloud证书,通常通过:
- 云函数附属服务账户(建议)
GOOGLE_APPLICATION_CREDENTIALS指向服务账户密钥文件的环境变量- Cloud 函数运行时环境的默认证书
处理错误 :
- 秘密检索过程中的任何错误: 返回空对象
{},允许该函数继续 - 错误被登录到控制台, 但不能失败引用
示例秘密结构:
在 Google 机密管理器中存储此 JSON projects/{project-id}/secrets/helix-deploy--my_package/versions/latest数字 :
{
"API_KEY": "your-api-key-here",
"DATABASE_URL": "postgresql://...",
"JWT_SECRET": "your-jwt-secret"
}
在您的函数中使用密钥 :
export async function main(request, context) {
// Secrets are automatically available in context.env and process.env
const apiKey = context.env.API_KEY;
const dbUrl = process.env.DATABASE_URL;
// Existing environment variables take precedence
// If API_KEY is already set in process.env, the secret won't override it
return new Response('OK');
}
禁用密钥插件 :
如果您想要禁用自动秘密加载 :
// Use the raw adapter without secrets plugin
import { lambda } from '@adobe/helix-universal';
export const handler = lambda.raw; // No secrets plugin
秘密测试 :
为了测试,你可以提供 模拟秘密使用 emulateEnv 选项 :
import { lambda, awsSecretsPlugin } from '@adobe/helix-universal';
const testLambda = lambda.raw.with(awsSecretsPlugin, {
emulateEnv: {
API_KEY: 'test-api-key',
TEST_MODE: 'true',
},
});
// Use testLambda in your tests
自定义插件
您可以创建自定义插件 :
function myPlugin(adapter, options) {
return async (event, context) => {
// Pre-processing
context.attributes.customData = 'value';
// Call the adapter
const response = await adapter(event, context);
// Post-processing
response.headers.set('x-custom-header', 'value');
return response;
};
}
const customAdapter = lambda.raw.with(myPlugin, { option: 'value' });
可用的插件包
海利克斯生态系统提供了几个预先建造的插件来扩展通用运行时的功能. 这些插件使用 包装工具 用于围绕您的功能构建中间软件.
机构数据插件 (单位:千美元)@ adobe/helix-share-body-data 数据(中文(简体) )
解析请求机构(JSON,窗体数据, URL-编码),并将数据以 context.data数字 :
import wrap from '@adobe/helix-shared-wrap';
import bodyData from '@adobe/helix-shared-body-data';
export const main = wrap(async (request, context) => {
// Access parsed body data
const { name, email } = context.data;
return new Response(`Hello ${name}!`);
})
.with(bodyData);
弹出插件 (单位:千美元)@ adobe/helix-shared-bounce (英语)(中文(简体) )
从慢跑函数提供快速的正式响应. 返回两个响应(快速响应器功能或慢主功能)的速度:
import wrap from '@adobe/helix-shared-wrap';
import bounce from '@adobe/helix-shared-bounce';
async function fastResponder(req, context) {
return new Response(`Processing... Use ${context.invocation.bounceId} to track status.`);
}
export const main = wrap(async (request, context) => {
// Slow operation
await doSlowWork();
return new Response('Done');
})
.with(bounce, { responder: fastResponder });
密钥插件 (单位:千美元)@adobe/helix-shared-secrets (英语)(中文(简体) )
装入云提供者秘密管理器(目前为 AWS 秘密管理器) 的秘密并添加到 context.env 财务报告和审定财务报表 process.env数字 :
import wrap from '@adobe/helix-shared-wrap';
import secrets from '@adobe/helix-shared-secrets';
export const main = wrap(async (request, context) => {
// Secrets are available in context.env
const apiKey = context.env.API_KEY;
return new Response('OK');
})
.with(secrets);
说明: 这与内置的秘密插件不同(awsSecretsPlugin 财务报告和审定财务报表 googleSecretsPlugin自动列入适配器。 这个 @adobe/helix-shared-secrets 插件提供了额外的自定义选项,并可用于自定义名称功能.
IMS 插件 (单位:千美元)@ adobe/helix-shared-ims (英语)(中文(简体) )
提供Adobe身份管理系统认证. 处理 OAuth2 流程,并提供用户配置文件 context.ims数字 :
import wrap from '@adobe/helix-shared-wrap';
import ims from '@adobe/helix-shared-ims';
export const main = wrap(async (request, context) => {
if (context.ims.profile) {
// User is authenticated
const { name, email, userId } = context.ims.profile;
return new Response(`Hello ${name}!`);
}
return new Response('Not authenticated', { status: 401 });
})
.with(ims, {
clientId: 'my-client-id',
env: 'prod',
forceAuth: true, // Require authentication
});
IMS 插件添加到以下 context.ims数字 :
context.ims.config: 解决了IMS配置context.ims.accessToken: 当前访问符context.ims.profile: 经认证的用户配置文件(名称、电子邮件、用户) (d) 国家
服务器计时插件 (单位:千美元)@adobe/helix-share-server-timing (原始内容存档于2012-09-26)(中文(简体) )
通过跟踪执行时间和添加添加性能监测 Server-Timing HTTP 标题 :
import wrap from '@adobe/helix-shared-wrap';
import serverTiming from '@adobe/helix-shared-server-timing';
export const main = wrap(async (request, context) => {
const { timer } = context;
timer.update('fetch-data');
const data = await fetchData();
timer.update('process-data');
const result = processData(data);
timer.update('render');
const html = render(result);
return new Response(html);
})
.with(serverTiming);
插件添加一个 timer 对象 context 带有 update(name) 用于记录执行里程碑的方法。 时间数据自动添加到 Server-Timing 响应头,可以在浏览器 DevTools 中查看.
组合多插件 :
您可以将多个插件连在一起 :
import wrap from '@adobe/helix-shared-wrap';
import bodyData from '@adobe/helix-shared-body-data';
import ims from '@adobe/helix-shared-ims';
import serverTiming from '@adobe/helix-shared-server-timing';
export const main = wrap(async (request, context) => {
// context.data - parsed body data
// context.ims.profile - authenticated user
// context.timer - performance timer
return new Response('OK');
})
.with(serverTiming)
.with(ims, { clientId: 'my-client-id' })
.with(bodyData);
说明: 执行命令被倒置 - 最后一个添加的插件先执行 .
解析器和版本锁定
解析器支持版本锁定,允许您通过 x-ow-version-lock 页眉 :
// Client sends header: x-ow-version-lock: content-proxy=1.2.3&dispatch=2.0.0
// In your function:
const url = context.resolver.createURL({
package: 'helix-services',
name: 'content-proxy',
version: '1.5.0', // This will be overridden to 1.2.3
});
完整示例
以下是一个通用函数的完整例子:
import { Response } from '@adobe/fetch';
export async function main(request, context) {
// Log request
context.log.info('Processing request', {
method: request.method,
url: request.url,
function: context.func.name,
version: context.func.version,
});
// Access environment variables
const apiKey = context.env.API_KEY;
// Invoke another function
const otherFunctionUrl = context.resolver.createURL({
package: 'helix-services',
name: 'content-proxy',
version: '1.2.3',
});
// Generate presigned URL
const presignedUrl = await context.storage.presignURL(
'my-bucket',
'path/to/file.jpg',
{},
'GET',
3600
);
// Process request
const body = await request.json();
// Return response
return new Response(JSON.stringify({
message: 'Success',
function: context.func.name,
runtime: context.runtime.name,
presignedUrl,
}), {
status: 200,
headers: {
'content-type': 'application/json',
},
});
}
类型脚本支持
包括类型定义。 视需要导入类型:
import type { UniversalContext, UniversalFunction } from '@adobe/helix-universal';
async function main(
request: Request,
context: UniversalContext
): Promise<Response> {
// TypeScript will provide full type checking
return new Response('OK');
}
发展
构建
$ npm install
测试
$ npm test
林特
$ npm run lint