出于好奇了解了下云函数(函数计算),各个服务商叫法不同,本质是一样的,对于开发者,无需关注服务环境配置,只需实现业务代码。尝试了一下阿里云OSS,HTTP,定时触发器的使用,整理了部分DEMO代码。
云函数特点
无服务器
无服务器并不是没有服务器就能够进行计算,而是对于开发者来说,无需了解底层的服务器情况,也能使用到相关资源,因此称为无服务器。
函数即服务
函数即服务提供了一种直接在云上运行无状态的、短暂的、由事件触发的代码的能力。
基本概念可以看下腾讯云文档:https://cloud.tencent.com/document/product/583/30558 了解️。
定时触发器
这里实现一个简单服务报警函数,新建定时触发器,比如每分钟轮询应用,通过状态码获取应用服务状态,异常即通过钉钉webhook机器人发送通知。
<?php
function handler($event, $context) {
$logger = $GLOBALS['fcLogger'];
$logger->info('开始执行');
$dingServer = "https://oapi.dingtalk.com/robot/send?access_token=xxxxx";
$statusCodes = [];
$statusCodes['mango_blog']['status_code'] = getStatusCode("https://blog.mango.im/favicon.ico");
$appStatus = statusCodeHandle($statusCodes);
if(!empty($appStatus)) {
$msg["msgtype"] = "text";
$msg["text"]["content"] = $appStatus;
sendDingMsg($dingServer, json_encode($msg));
$logger->info("报警信息:".json_encode($msg));
} else {
$logger->info("所有应用服务正常");
}
return json_encode($appStatus);
}
function getStatusCode($url) {
$curlHandle = curl_init();
curl_setopt($curlHandle, CURLOPT_URL, $url);
curl_setopt($curlHandle, CURLOPT_HEADER, true);
curl_setopt($curlHandle, CURLOPT_NOBODY , true);
curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, true);
curl_exec($curlHandle);
$response = curl_getinfo($curlHandle, CURLINFO_HTTP_CODE);
curl_close($curlHandle);
return $response;
}
function sendDingMsg($dingServer, $msg) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $dingServer);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_HTTPHEADER, array ('Content-Type: application/json;charset=utf-8'));
curl_setopt($ch, CURLOPT_POSTFIELDS, $msg);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
function statusCodeHandle($statusCodes) {
$appStatus = [];
foreach($statusCodes as $app => $statusCode) {
if($statusCode['status_code'] != 200) {
$appStatus[$app] = "报警:服务挂了!!😱".$statusCode['status_code'];
}
}
return $appStatus;
}
HTTP 触发器
HTTP 触发器比较强,可以直接构建WEB服务,绑定自定义域名就可以了。对于需要数据库应用,比如WordPress可能需要云数据库支持。
这里演示基本DEMO:http://pi.mango.im/
注意:Http Trigger 会自动在响应头中强制添加 ‘Content-Disposition: attachment’ 字段,此字段会使得返回结果在浏览器中以附件的方式下载。此字段无法覆盖,使用自定义域名可以避免该问题。
<?php
use RingCentral\Psr7\Response;
/*
To enable the initializer feature (https://help.aliyun.com/document_detail/89029.html)
please implement the initializer function as below:
function initializer($context) {
echo 'initializing' . PHP_EOL;
}
*/
function handler($request, $context): Response{
/*
$body = $request->getBody()->getContents();
$queries = $request->getQueryParams();
$method = $request->getMethod();
$headers = $request->getHeaders();
$path = $request->getAttribute('path');
$requestURI = $request->getAttribute('requestURI');
$clientIP = $request->getAttribute('clientIP');
*/
return new Response(
200,
array(
'custom_header1' => 'v1',
'custom_header2' => ['v2', 'v3'],
// content-type: text/html; charset=UTF-8
'content-type' => 'text/html; charset=UTF-8'
),
'hello world'
);
}
对象存储(OSS)触发器
创建对象存储触发器,并授予OSS权限。比如:oss:ObjectCreated.*,上传文件即触发,下面函数为官方demo,上传图片改变文件大小。
<?php
use OSS\OssClient;
/*
To enable the initializer feature (https://help.aliyun.com/document_detail/89029.html)
please implement the initializer function as below:
function initializer($context) {
$logger = $GLOBALS['fcLogger'];
$logger->info('initializing');
}
*/
function handler($event, $context) {
$logger = $GLOBALS['fcLogger'];
$logger->info('hello world');
resize($event, $context);
return 'hello world';
}
function resize($event, $context) {
$event = json_decode($event, $assoc = true);
$accessKeyId = $context["credentials"]["accessKeyId"];
$accessKeySecret = $context["credentials"]["accessKeySecret"];
$securityToken = $context["credentials"]["securityToken"];
$evt = $event['events'][0];
$bucketName = $evt['oss']['bucket']['name'];
$endpoint = 'oss-' . $evt['region'] . '.aliyuncs.com';
$objectName = $evt['oss']['object']['key'];
$newKey = str_replace("source/", "processed/", $objectName);
try {
$ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, false, $securityToken);
$content = $ossClient->getObject($bucketName , $objectName);
if ($content == null || $content == "") {
return;
}
$imagick = new Imagick();
$imagick->readImageBlob($content);
$imagick->resizeImage(128, 128, Imagick::FILTER_LANCZOS, 1);
$ossClient->putObject($bucketName, $newKey, $imagick->getImageBlob());
} catch (OssException $e) {
print($e->getMessage());
}
}
体验了一波云函数,感觉对于特定或独立的服务是可以尝试用下的。具体还是要看业务需求是否适用。