云函数的概念与原理
1.云函数的概念
云函数(Serverless Cloud Function,SCF)是腾讯云为企业和开发者们提供的无服务器执行环境,帮助您在无需购买和管理服务器的情况下运行代码。您只需使用平台支持的语言编写核心代码并设置代码运行的条件,即可在腾讯云基础设施上弹性、安全地运行代码。SCF 是实时文件处理和数据处理等场景下理想的计算平台。
2.无服务器的概念
无服务器(Serverless)不是表示没有服务器,而表示当您在使用 Serverless 时,您无需关心底层资源,也无需登录服务器和优化服务器,只需关注最核心的代码片段,即可跳过复杂的、繁琐的基本工作。核心的代码片段完全由事件或者请求触发,平台根据请求自动平行调整服务资源。Serverless 拥有近乎无限的扩容能力,空闲时,不运行任何资源。代码运行无状态,可以轻易实现快速迭代、极速部署。
3.函数即服务
函数即服务提供了一种直接在云上运行无状态的、短暂的、由事件触发的代码的能力。
函数即服务和传统应用架构不同,函数服务提供的是事件触发式的运行方式,云函数不是始终运行的状态,而是在事件发生时由事件触发运行,并且在一次运行的过程中处理这一次事件。因此在云函数的代码中,仅需考虑针对一个事件的处理流程,而针对大量事件的高并发处理,由平台实现云函数的多实例并发来支持。
为了实现对高并发的支持,云函数平台提供了自动的弹性伸缩能力,会在有大量请求到来时启动更多实例来处理事件请求,也会在没有事件到来时缩减函数实例甚至到零实例。因此为了匹配自动扩缩能力,需要函数代码使用的是无状态开发方式,即不在云函数的运行内存中保留相关的状态数据并在多次运行时依赖这些状态数据。云函数的状态数据,可以依赖外部的持久存储能力例如云缓存、云数据库、云存储来进行。
4.触发器和触发源
任何可以产生事件,触发云函数执行的均可以被称为触发器或触发源。触发器在本身产生事件后,通过将事件传递给云函数来触发函数运行。
触发器在触发函数时,可以根据自身特点,使用同步或异步方式触发函数。同步方式触发函数时,触发器将等待函数执行完成并获取到函数执行结果;异步方式触发函数时,触发器将仅触发函数而忽略函数执行结果。
腾讯云云函数在和腾讯云的某些产品或服务对接时,也有自身实现的一些特殊方式,例如推(PUSH)模式和拉(PULL)模式。
- 推模式:触发器主动将事件推送至云函数平台并触发函数运行。
- 拉模式:云函数平台通过拉取模块,从触发器中拉取到事件并触发云函数运行。
5.使用流程
以下为云函数使用流程图及基本步骤简介:
- 准备工作:包含注册腾讯云账号、开通云函数服务、配置基本开发环境等。
- 编写函数:函数是调度与运行的基本单元,编写函数时需遵循函数接口规范。
- 本地测试:可在本地进行代码调试,并将代码部署到云端。
- 部署函数(含配置触发器):代码部署到云端后,云函数可在配置好条件后执行函数。函数的执行条件被称为触发器,您可以配置定时、API 网关、COS 等多种触发器。
- 云端测试:函数在云端部署完成后,可通过已配置的触发方式测试云函数。
- 查看日志:云函数支持以多种方式查看历史或实时的函数日志。
- 查看监控:可通过查看监控指标,了解函数运行的状况。
- 配置告警:对于线上生产业务非常关键。在配置告警后,当业务出现异常情况,您可以及时收到告警信息。
6.开发指南
执行方法
SCF 平台在调用云函数时,首先会寻找执行方法作为入口,执行用户的代码。此时,用户需以文件名. 执行方法名的形式进行设置。例如,用户设置的执行方法为 index.handler
,则 SCF 平台会首先寻找代码程序包中的 index
文件,并找到该文件中的 handler
方法开始执行。在编写执行方法时,用户需遵循平台特定的编程模型。如下所示:
1 | def method_name(event,context): |
该模型中指定固定的 event 事件数据和 context 环境数据作为入参。在执行方法中,用户需对参数进行处理,并且可任意调用代码中的任何其他方法。
函数入参
函数入参,是指函数在被触发调用时所传递给函数的内容。通常情况下,函数入参包括 event 入参和 context 入参两部分,但根据开发语言和环境的不同,入参个数可能有所不同。
event 入参
作用
参数类型为 dict
。将 event 入参传递给执行方法,实现代码与触发函数的事件(event)交互。例如,由于文件上传触发了函数运行,代码可从 event 参数中获取该文件所有信息,包括文件名、下载路径、文件类型、大小等。
使用说明
针对不同的函数情况,event 参数的值有以下区别:
- 云服务触发函数时,云服务会将事件以一种平台预定义的、不可更改的格式作为 event 参数传给 SCF 函数,您可以根据此格式编写代码并从 event 参数中获取信息。例如,COS 触发函数时会将 Bucket 及文件的具体信息以 JSON 格式传递给 event 参数。
- 云函数被其他应用程序调用时,您可以在调用方和函数代码之间自定义一个
dict
类型的参数。调用方按照定义好的格式传入数据,函数代码按格式获取数据。例如,定义一个dict
类型的数据结构{"key":"XXX"}
,当调用方传入数据{"key":"abctest"}
时,函数代码可以通过event[key]
来获得值abctest
。
context 入参
作用
将 context 入参传递给执行方法,代码将通过 context 入参对象,了解到运行环境及当前请求的相关内容。
使用说明
请参考以下 context 入参,了解具体信息:
1 | { |
其中包括了当前调用的执行超时时间,内存限制,以及当次请求 ID。
WEB 函数的概念与原理
WEB 函数
Web 函数(Web Function)是云函数的一种函数类型,区别于事件函数(Event Function)对于事件格式的限制,专注于优化 Web 服务场景,用户可以直接发送 HTTP 请求到 URL 触发函数执行。
运行原理
Web 函数运行原理如下图所示:
用户发送的 HTTP 请求经过 API 网关后,网关侧将原生请求直接透传的同时,在请求头部添加了网关触发函数时需要的函数名、函数地域等内容,并一起传递到函数环境,触发后端函数执行。
函数环境内,通过内置的 Proxy 实现 Nginx 转发,并去除头部非产品规范的请求信息,将原生 HTTP 请求通过指定端口发送给用户的 Web Server 服务。
用户的 Web Server 配置好指定的监听端口9000
和服务启动文件后部署到云端,通过该端口获取 HTTP 请求并进行处理。
API 网关触发机制
API 网关触发器的集成请求事件消息结构
在 API 网关触发器接收到请求时,会将类似以下 JSON 格式的事件数据发送给绑定的云函数。
1 | { |
数据结构内容详细说明如下:
结构名 | 内容 |
---|---|
requestContext | 请求来源的 API 网关的配置信息、请求标识、认证信息、来源信息。其中:serviceId,path,httpMethod 指向 API 网关的服务 ID、API 的路径和方法。stage 指向请求来源 API 所在的环境。requestId 标识当前这次请求的唯一 ID。identity 标识用户的认证方法和认证的信息。sourceIp 标识请求来源 IP。 |
path | 记录实际请求的完整 Path 信息。 |
httpMethod | 记录实际请求的 HTTP 方法。 |
queryString | 记录实际请求的完整 Query 内容。 |
body | 记录实际请求转换为 String 字符串后的内容。 |
headers | 记录实际请求的完整 Header 内容。 |
pathParameters | 记录在 API 网关中配置过的 Path 参数以及实际取值。 |
queryStringParameters | 记录在 API 网关中配置过的 Query 参数以及实际取值。 |
headerParameters | 记录在 API 网关中配置过的 Header 参数以及实际取值。 |
API 网关触发器的集成响应返回数据结构
在 API 网关设置为集成响应时,需要将包含以下 JSON 格式的数据结构返回给 API 网关。
1 | { |
数据结构内容详细说明如下:
结构名 | 内容 |
---|---|
isBase64Encoded | 指明 body 内的内容是否为 Base64 编码后的二进制内容,取值需要为 JSON 格式的 true 或 false。 |
statusCode | HTTP 返回的状态码,取值需要为 Integer 值。 |
headers | HTTP 返回的头部内容,取值需要为多个 key-value 对象,或 key:[value,value] 对象。其中 key、value 均为字符串。headers 请求头暂不支持 Location key。 |
body | HTTP 返回的 body 内容。 |
WEB 函数的实际应用
创建 WEB 函数
1.访问腾讯云云函数:https://console.cloud.tencent.com/scf/list
2.选择地区
3.新建云函数,选择自定义模板。为了测试云函数,代码先选择默认的
4.配置 触发器,选择 api 网关
- 访问云函数
- 查看访问日志
浏览器访问,返回 403
查看日志,可以看到来源 ip 和请求方法,请求服务,请求路径等等
修改 WEB 函数的返回内容为下面代码,在通过浏览器访问就会正常了。至此,WEB 函数的实际使用流程走通了
1 | a = {"isBase64Encoded": False,"statusCode": 200,"headers": {"Content-Type":"text/html"},"body": "<html><body><h1>Heading</h1><p>Paragraph.</p></body></html>"} |
HTTP 代理测试
实现 GET 型类 SSRF
在 WEB 函数中,可以使用 queryString 字段来获取 GET 请求的参数
1 | # -*- coding: utf8 -*- |
浏览器访问效果如下:
访问百度
访问 http://tool.chinaz.com/ipwhois,查看 ip
POST 型类 SSRF
将 WEB 函数改为下面这样
1 | # -*- coding: utf8 -*- |
通过在线 http 接口测试工具,来验证 WEB 函数
3.HTTP 代理 DEMO
云函数可利用 API 网关触发器进行触发,接受来自客户端的数据,然后云函数可以对外发包,类似于一个 SSRF。
因此一个 HTTP 代理的实现思路就很简单了。本地客户端通过代理发送数据包,HTTP 代理服务器拦截数据包,提取 HTTP 报文相关信息,然后将报文以 JSON 格式 POST 到云函数进行解析,云函数根据解析到的信息对目标发起请求,最终将结果一层一层返回到客户端。
服务端依旧使用上面的 POST 型的 SSRF 代码,然后部署在 WEB 函数里,用来做代理请求公网资源。
客户端代码实现如下:
客户端是代理本地端口,接收浏览器请求,然后将请求转发给 web 函数,并接收 web 函数的返回结果,再将 web 函数的返回结果返回给浏览器。
1 | #!/usr/bin/python3 |
浏览器配置代理
访问百度
4.改进:HTTP 代理 DEMO
上面的 HTTP 代理 DEMO 有个很明显的短板,服务端使用 resp = requests.get(url) 来请求公网资源,只支持 GET 方法;本地客户端代理使用 url = re.findall(r”GET (.*?) HTTP/1.1”, request_str)[0] 来提取来自浏览器的 url,也是只能提取到 GET 方法。
然后 HTTP 协议是支持 8 中请求方法的,所以为了实现完全的 HTTP 代理,要改进 demo 代码。
服务端代理改进后代码如下:
1 | # -*- coding: utf8 -*- |
客户端代理改进后代码如下:
1 | #!/usr/bin/python3 |
参考链接:https://cloud.tencent.com/document/product/583
- 本文作者: ordar
- 本文链接: https://mrwq.github.io/云函数实现类SSRF/
- 版权声明: 本文作者: ordar123 转载请注明出处!