华为云函数工作流 FunctionGraph 写一个简单 HTTP 触发器函数的实践
很多内部小接口并不值得单独买一台常驻云服务器。查询一段配置、做健康检查、把一次表单提交收成一条记录,这类请求量不稳定、逻辑又很短的接口,更适合放到函数工作流 FunctionGraph 上:没有调用时不计运行时长,有请求时由 HTTP 触发器拉起函数并返回响应。下面按控制台的真实顺序,写一个只做参数校验和回显的 Python 函数,骨架可以直接换成自己的业务。
先确认用的是 HTTP 函数
函数工作流里有两类函数。事件函数靠定时器、对象存储、消息通知等事件拉起,入口参数是各服务自己的事件结构。HTTP 函数专门接收 HTTP h��求,创建完成后就会有调用地址,不必再单独买一台云服务器,也不必先学完整的网关配置。本文只写 HTTP 函数。
打开函数工作流控制台,进入「函数」列表,选择「创建函数」,类型选 HTTP 函数,不要选事件函数。运行时选择 Python 3.9。Python 3.6 已不适合新函数,官方依赖和示例都在往 3.9 及更新版本收。内存先用 128 MB,执行超时设为 3 秒。函数名用业务前缀,例如 http_echo_demo,避免以后列表里全是 test、demo1 这类分不清用途的名字。
执行入口填 index.handler。这表示平台去加载文件 index.py,并调用其中名为 handler 的函数。入口和文件名必须一致:入口是 index.handler 时,在线编辑里的文件就要是 index.py;如果改成 main.handler,文件也要改成 main.py。两边不一致时,测试会报找不到模块,日志里看不到你的业务打印,容易误以为是触发器没配对。
请求在 event 里长什么样
HTTP 触发器把一次请求装进字典交给 handler,签名是 handler(event, context)。和定时触发器相比,这里要读的是方法、路径、查询参数和请求体:
- 方法在
httpMethod,取值如 GET、POST。 - 查询参数在
queryStringParameters。调用方没带任何参数时,这个字段可能是空值,而不是空字典,取之前要先兜底。 - 请求体在
body,通常是字符串。JSON 要自己解析。 - 如果调用方或平台用了 Base64,以
isBase64Encoded为准,为真时要先解码再解析。
返回值不要只 return 一段普通字符串。平台认的是一个字典,里面至少有 statusCode 和 body。body 必须已经是字符串,业务字典要先序列化。响应头建议写上 Content-Type,并带上 charset=utf-8,否则部分客户端里的中文会乱码。序列化时使用 ensure_ascii=False,响应里就是中文,而不是一长串转义。
把下面的代码保存为 index.py:
import json
def handler(event, context):
event = event or {}
method = (event.get("httpMethod") or "GET").upper()
query = event.get("queryStringParameters") or {}
name = str(query.get("name") or "").strip()
if method != "GET":
return _resp(405, {"error": "only GET is allowed"})
if not name:
return _resp(400, {"error": "missing query name"})
if len(name) > 32:
return _resp(400, {"error": "name too long"})
return _resp(200, {"message": "hello", "name": name})
def _resp(code, payload):
return {
"statusCode": code,
"isBase64Encoded": False,
"headers": {"Content-Type": "application/json; charset=utf-8"},
"body": json.dumps(payload, ensure_ascii=False),
}
这段逻辑故意做得很小:只接受 GET,查询参数 name 必填且不超过 32 个字符,合法时回显。先把协议跑通,再把 name 的判断换成真实查询。
用测试事件确认,再打开外网调用
函数保存后,不要立刻把地址发给别人。在函数详情的测试里选择 HTTP 或 API 网关事件模板,把 queryStringParameters 改成只含 name 的对象,例如 name 的值写 huawei,然后执行。期望状态码 200,body 里 message 为 hello,name 为刚才传入的值。再执行一次去掉 name 的事件,应返回 400,错误信息是 missing query name。把方法改成 POST,应返回 405。
这三次分别覆盖成功、缺参、方法不对。三次都符合预期,才说明入口、返回结构、字符集都没问题。如果测试直接失败且日志里是模块找不到,回到入口和文件名;如果平台报执行失败而不是你返回的 400,多半是返回值不是字典,或者 body 里塞了字典而不是字符串。
测试通过后再看调用地址。HTTP 函数的触发器页会给出 URL,认证方式调试阶段可以先选「无认证」,用浏览器或命令行带上查询参数 name 访问路径。确认通了以后,再改成 IAM 或应用认证。无认证只适合内测,不要带着无认证的地址长期放在公网,否则任何人都能触发函数,调用次数和日志都会上来。
上线前值得看的五个细节
第一,冷启动。函数闲置一段时间后,下一次调用要重新初始化运行时,耗时会比热调用长。健康检查如果把超时卡在几百毫秒,可能把冷启动误判成故障。执行超时留 3 秒一般够用。流量本来就很小的时候,不必再加定时触发器去预热,预热本身也会计入调用。
第二,依赖不要把本机虚拟环境整包塞进在线编辑。只用标准库时,上面的 index.py 就够了。需要第三方库时,使用函数的依赖包,并保证依赖包的 Python 版本和函数运行时一致。3.9 打出来的包不要挂到别的运行时上,否则导入阶段就会失败,业务代码一行都走不到。
第三,不要把口令、访问密钥写进 index.py,也不要写进测试事件。函数需要访问其他云服务时,在配置里绑定委托,代码使用运行环境提供的临时凭证。测试事件经常会被人复制到工单或博客里,里面出现过一次真实密钥,就等于公开了。
第四,看日志要分清两类失败。函数返回 400 或 405,说明代码已经执行,只是参数或方法不合法,去对调用方。平台返回 502 一类错误,或者日志里完全没有这次调用,优先检查入口名、返回结构,以及触发器是否允许了对应的方法。触发器没放开 GET 时,请求在入口层就被拒绝,函数日志里不会出现你的 print。
第五,路径、方法和函数内的判断要一起改。函数拒绝 POST,但触发器仍开放 POST,调用方拿到的 405 是函数主动返回的,这是预期。反过来,函数支持了新方法,触发器忘了勾选,调用方看到的是网关或平台错误,怎么改 index.py 都不会生效。改协议时两处一起改,并再用测试事件走一遍。
按这个顺序,一个只做校验和回显的 HTTP 函数就可以稳定跑通。下一步把校验通过之后的分支换成真实逻辑,例如读取函数环境变量里的配置项,或通过委托访问其他云服务。handler 的签名、_resp 的返回结构、测试三次的习惯都可以留着,不必推倒重来。
- 点赞
- 收藏
- 关注作者
评论(0)