云函数初探

于好奇了解了下云函数(函数计算),各个服务商叫法不同,本质是一样的,对于开发者,无需关注服务环境配置,只需实现业务代码。尝试了一下阿里云OSS,HTTP,定时触发器的使用,整理了部分DEMO代码。

云函数特点

无服务器

无服务器并不是没有服务器就能够进行计算,而是对于开发者来说,无需了解底层的服务器情况,也能使用到相关资源,因此称为无服务器。

函数即服务

函数即服务提供了一种直接在云上运行无状态的、短暂的、由事件触发的代码的能力。

基本概念可以看下腾讯云文档:https://cloud.tencent.com/document/product/583/30558 了解️。

定时触发器

这里实现一个简单服务报警函数,新建定时触发器,比如每分钟轮询应用,通过状态码获取应用服务状态,异常即通过钉钉webhook机器人发送通知。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?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’ 字段,此字段会使得返回结果在浏览器中以附件的方式下载。此字段无法覆盖,使用自定义域名可以避免该问题。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?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,上传图片改变文件大小。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?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());
    }
 } 

体验了一波云函数,感觉对于特定或独立的服务是可以尝试用下的。具体还是要看业务需求是否适用。

updatedupdated2020-09-132020-09-13
Load Comments?