Serverless 文件上传优化

作者:
发布于: 2021-1-26
归档于:

标签:ServerlessAPI 网关

前言

当开发者需要搭建一个 Web 应用或移动端程序时,可以使用云函数作为后端服务,由 API 网关接收客户端请求,并触发云函数处理。这样的 Serverless 架构具备简单便捷、可弹性扩展、高可用等优势,正成为越来越多人的共同选择。

但开发者在搭建应用时,难免会遇到上传文件的场景,如 App 上传用户头像、个人博客文章图片、网站评论图片,这些都需要上传文件到后端。如果您的业务托管在主机上,上传文件往往不受限制,可使用 multipart/form-data 方式直接上传文件;但在 Serverless架构下,由于 API 网关和云函数之间只支持传输 JSON 数据,使用传统方式上传文件较为困难,一般的解决方案是由客户端通过 Base64 等算法,先将文件从二进制转换为字符后再进行上传。

近期腾讯云 Serverless 团队优化了上传文件体验,上线了 API 网关 Base64 编码功能,上传文件时原本由客户端做的 Base64 编码过程变为由 API 网关进行,这使得开发者无需改动客户端代码即可将二进制文件上传至云函数 SCF。同时,前端开发中一般可基于 Base64 格式完成图片的存储和展现,使得该功能对前端开发者来说非常友好。

本文对 Serverless 和传统方式 multipart 上传多文件的过程进行了对比,并介绍了Base64 编码功能的配置方式。

请求过程对比

传统方式上传文件过程

如果您的后端服务托管在云主机上,一般上传文件的请求过程如下:

  • 第一步:客户端可直接使用 multipart/form-data 方式上传文件;
  • 第二步:在后端服务中获取二进制文件。

以下是一段客户端上传两张图片 pic-1.jpg 和 pic-2.jpg 到后端服务的 Python 3 参考代码:

复制代码
import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder
from requests_toolbelt.multipart import decoder
 
m = MultipartEncoder(
    fields=[
           ('files[]',('file.jpg', open('pic-2.jpg', 'rb'), 'image/jpeg')),
           ('files[]',('file2.jpg', open('pic-1.jpg', 'rb'), 'image/jpeg')),
           ]
    )

res = requests.post(url='https://yourwebsite.com/upload',
                    data=m,
                    headers={'Content-Type': m.content_type})
json = res.json()
print(json)

Serverless 上传文件过程

如图是采用 API 网关结合云函数,开启 Base64 功能后上传文件的请求过程:

  1. 客户端可直接使用 multipart/form-data 方式上传文件;
  2. 在云函数中获取经过 Base64 编码的文本。

对比结论

通过以上两种方式的对比,我们不难看出,Base64编码功能的最大优势在于使 Serverless 获得了和传统方式完全一致的上传文件体验,可直接使用传统方式的客户端代码进行上传。

另外,在云函数中获取了经过 Base64 编码的文本后,您只需对 event.body 进行解码,就可以得到二进制文件了。以下是一段在云函数中解码多文件的 Python 3 参考代码:

复制代码
# -*- coding: utf-8 -*-

import sys
import logging
import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder
from requests_toolbelt.multipart import decoder
import base64
import json

print('Loading function')

logger = logging.getLogger()

def main_handler(event, context):
    logger.info("start main handler")

    content_type_header = event['headers']['content-type']
    body = event['body']
    is_me = base64.b64decode(body)
    for part in decoder.MultipartDecoder(is_me, content_type_header).parts:
        print(part.content)

注意:需要使用层或上传 zip 包的形式安装相关依赖。

实战配置

为满足不同场景的要求,Base64 编码功能还提供了“全部触发”和“Header 触发”两种触发方式供您选择:

  • 全部触发:API 开启全部触发后,每次请求的请求内容都会被 Base64 编码后再传递给云函数。
  • Header 触发:API 开启 Header 触发后,必须配置触发规则。API 网关将根据触发规则对请求头进行校验,只有拥有特定 Content-Type 或 Accept 请求头的请求会被 Base64 编码后再传递给云函数,不满足条件的请求将不进行 Base64 编码,直接传递给云函数。

以下将分别叙述两种触发方式的配置过程:

配置全部触发

  1. 登录 API 网关控制台 ,在左侧导航栏单击【服务】。
  2. 在服务列表中,单击目标服务的服务 ID,查看 API 列表。
  3. 单击【新建】,填写 API 前端配置,单击【下一步】。
  4. API 后端类型选择【云函数SCF】,勾选“Base64编码”,完成后续配置流程。此时创建的 API 已经开启了 Base64 编码,并默认为“全部触发”。

配置 Header 触发

  1. 登录 API 网关控制台 ,在左侧导航栏单击【服务】。
  2. 在服务列表中,单击目标服务的服务 ID,查看 API 列表。
  3. 在 API 列表中,单击目标 API 的 API ID(目标 API 必须是后端对接 SCF 的 API),即可查看 API 详情页。 在 API 详情页中,单击【基础配置】标签页,找到【Base64编码】配置项。
  4. 单击"Base64"后的【编辑】,选择触发方式为【Header触发】。单击【添加触发规则】,选择参数并填写参数值。
  5. 确认配置信息无误后,最后单击【保存】即可。




传送门:

欢迎访问:Serverless 中文网,您可以在 最佳实践 里体验更多关于 Serverless 应用的开发!