前言
Serverless(无服务器架构)逐渐成为了主流趋势,阿里云、腾讯云都有自己的 Serverless 产品,函数计算和云函数的使用越来越多。而无服务器架构无法存储任何文件,PHP中也无法使用$_FILES
等预定义数组,因此在传统服务器端开发中的一个简单需求,在 Serverless 中成为了个麻烦的事情。
比如场景中接收用户头像上传,然后存储到 OSS、COS、或其他存储容器中,最后返回上传结果(url)。当然,直接上传至 OSS、COS、存储容器会是更好的方式,因为阿里云和腾讯云都对 HTTP 的 Request 和 Response 的 Body 大小进行了限制(6MB)。
本文即对阿里云的函数计算以及腾讯云的云函数的文件上传提供解决方案。
通用解决方案
一种通用解决方案是,客户端提交的数据是application/json
格式,将文件进行base64编码后 POST 提交,函数端进行base64_decode
即可。
阿里云
阿里云的解决方案比较简单,只需要解析 POST 提交为Content-Type: multipart/form-data
的数据即可,这里可以直接用 ReactPHP 的 http MultipartParser类:
https://github.com/reactphp/http/blob/master/src/Io/MultipartParser.php
在代码中对该文件进行引用,然后解析 form-data 数据即可,假设 form-data 提交上来的图片 key 是 image:
function handler($request, $context): Response{
$parsedRequest = (new MultipartParser())->parse($request);
$file = $parsedRequest->getUploadedFiles();
$fileImage = $file['image'];
$fileName = $fileImage->getClientFilename();
}
然后将该文件上传至 OSS:
try {
$ossClient = new OssClient('accessKeyId', 'accessKeySecret', 'endpoint');
// 这里将stream进行base64编码再解码,转换为二进制数据流
$result = $ossClient->putObject('bucket', 'object', base64_decode(base64_encode($fileImage->getStream())));
echo $result['info']['url'];
}
catch(OssException $e) {
echo $e->getMessage();
}
腾讯云
腾讯云的解决方式比较麻烦,云函数只对application/json
的提交数据比较友好,因此需要用到API网关功能来解决。
首先在函数的触发管理中创建API网关触发的触发器:
然后进入云函数的API网关面板,在服务中找到对应函数的API网关(对应云函数触发管理中的serviceId),进入网关API管理页面后,找到相应的函数。
点击进入函数,点击上方的基础设置,找到Base64编码栏,设置Base64编码为Header触发:
最后,在代码端进行解析即可,base64_decode
出来的数据和 form-data 的原始数据是相同的:
function main_handler($event, $context) {
$body = json_decode($event->body, true);
if(!$body) {
$body = base64_decode($event->body);
}
}
可以通过使用上文阿里云解决方案中的 form-data 解析类进行解析,
官方也提供了一篇文件上传的实践文档:https://cloud.tencent.com/document/product/583/52991
快更新!
催更!