千家信息网

如何基于Serverless使用 SCF+COS 给未来写封信

发表于:2024-11-14 作者:千家信息网编辑
千家信息网最后更新 2024年11月14日,这期内容当中小编将会给大家带来有关如何基于Serverless使用 SCF+COS 给未来写封信,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。或许你有用过或者听说过
千家信息网最后更新 2024年11月14日如何基于Serverless使用 SCF+COS 给未来写封信

这期内容当中小编将会给大家带来有关如何基于Serverless使用 SCF+COS 给未来写封信,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

或许你有用过或者听说过《给未来写封信》,这是由全知工坊开发的一款免费应用,你可以在此刻给自己或他人写下一封信,然后选择在未来的某一天寄出,想必那时收到信的人看着这封来自过往的信时一定会十分感动吧。

这次我就带大家一起来使用无服务器云函数 SCF 和对象存储 COS,快速开发一个属于自己的「给未来写封信」应用。

效果展示

写下一封信,然后投递:

一封来自很久以前的信:

写给未来的自己

你也可以访问letter.idoo.top/letter来亲自体验一下(仅供测试之用,不保证服务一直可用)

操作步骤

第一步:新建 python 云函数

参见我之前的系列文章《万物皆可 Serverless 之使用 SCF+COS 快速开发全栈应用》

第二步:编写云函数

Life is short, show me the code.

老规矩,直接上代码

import jsonimport datetimeimport randomfrom email.mime.text import MIMETextfrom email.header import Headerimport smtplib# 是否开启本地debug模式debug = False# 腾讯云对象存储依赖if debug:    from qcloud_cos import CosConfig    from qcloud_cos import CosS3Client    from qcloud_cos import CosServiceError    from qcloud_cos import CosClientErrorelse:    from qcloud_cos_v5 import CosConfig    from qcloud_cos_v5 import CosS3Client    from qcloud_cos_v5 import CosServiceError    from qcloud_cos_v5 import CosClientError# 配置存储桶appid = '66666666666'secret_id = 'xxxxxxxxxxxxxxx'secret_key = 'xxxxxxxxxxxxxxx'region = 'ap-chongqing'bucket = 'name'+'-'+appid#配置发件邮箱mail_host = "smtp.163.com"mail_user = "xxxxxxxxxx@163.com"mail_pass = "xxxxxxxxxxxxxx"mail_port = 465# 对象存储实例config = CosConfig(Secret_id=secret_id, Secret_key=secret_key, Region=region)client = CosS3Client(config)#smtp邮箱实例smtpObj = smtplib.SMTP_SSL(mail_host, mail_port)# cos 文件读写def cosRead(key):    try:        response = client.get_object(Bucket=bucket, Key=key)        txtBytes = response['Body'].get_raw_stream()        return txtBytes.read().decode()    except CosServiceError as e:        return ""def cosWrite(key, txt):    try:        response = client.put_object(            Bucket=bucket,            Body=txt.encode(encoding="utf-8"),            Key=key,        )        return True    except CosServiceError as e:        return False#获取所有信件def getletters():    letterMap = {}    letterTxt = cosRead('letters.txt')  # 读取数据    if len(letterTxt) > 0:        letterMap = json.loads(letterTxt)    return letterMap#添加信件def addletter(date, email, letter):    letterMap = getletters()    if len(letterMap) > 0:        letterMap[date+'_'+randomKey()] = email+'|'+letter    return cosWrite('letters.txt', json.dumps(letterMap, ensure_ascii=False)) if len(letterMap) > 0 else False#删除信件def delletter(letter):    letterMap = getletters()    if len(letterMap) > 0:        letterMap.pop(letter)    return cosWrite('letters.txt', json.dumps(letterMap, ensure_ascii=False)) if len(letterMap) > 0 else False# 获取今日日期def today():    return datetime.datetime.now().strftime("%Y-%m-%d")# 判断信件是否到期def checkDate(t):    return t[0:10] == today()# 根据时间生成uuiddef randomKey():    return ''.join(random.sample('zyxwvutsrqponmlkjihgfedcba0123456789', 6))# api网关回复消息格式化def apiReply(reply, html=False, code=200):    htmlStr = r'''            给未来的自己写封信        

开始写信

开始写信

送信日期

投递
''' return { "isBase64Encoded": False, "statusCode": code, "headers": {'Content-Type': 'text/html' if html else 'application/json', "Access-Control-Allow-Origin": "*"}, "body": htmlStr if html else json.dumps(reply, ensure_ascii=False) }#登陆邮箱def loginEmail(): try: smtpObj.login(mail_user, mail_pass) return True except smtplib.SMTPException as e: print(e) return False#发送邮件def sendEmail(letter): temp=letter.split('|') receivers = [temp[0]] message = MIMEText(temp[1], 'plain', 'utf-8') message['From'] = mail_user message['To'] = temp[0] message['Subject'] = '一封来自很久以前的信' try: smtpObj.sendmail(mail_user, receivers, message.as_string()) print("send email success") return True except smtplib.SMTPException as e: print("Error: send email fail") return False#每天定时检查需要发送的信件def check_send_letters(): loginEmail() letters = getletters() for date in letters.keys(): if checkDate(date): sendEmail(letters[date])def main_handler(event, context): if 'Time' in event.keys(): # 来自定时触发器 check_send_letters() return if 'httpMethod' in event.keys(): # 来自api网关触发器 if event['httpMethod'] == 'GET': return apiReply('', html=True) # 返回网页 if event['httpMethod'] == 'POST': # 添加信件 body = json.loads(event['body']) flag = addletter(body['date'], body['email'], body['letter']) return apiReply({ 'ok': True if flag else False, 'message': '添加成功' if flag else '添加失败' }) return apiReply('', html=True)

没错,这就是前面展示的网页应用的全部源码了,使用云函数 SCF 构建一个完整的前后端的全栈应用就是这么简单。

代码可能有点长,其实也没多少知识点,下面咱们再一起捋一下这个云函数 ~

import jsonimport datetimeimport randomfrom email.mime.text import MIMETextfrom email.header import Headerimport smtplib# 是否开启本地debug模式debug = False# 腾讯云对象存储依赖if debug:    from qcloud_cos import CosConfig    from qcloud_cos import CosS3Client    from qcloud_cos import CosServiceError    from qcloud_cos import CosClientErrorelse:    from qcloud_cos_v5 import CosConfig    from qcloud_cos_v5 import CosS3Client    from qcloud_cos_v5 import CosServiceError    from qcloud_cos_v5 import CosClientError

首先是依赖的导入,这里主要导入了 python 自带的 email 模块和腾讯云对象存储 SDK,来实现信件的发送和后端存储需求。

这里需要注意一点,在腾讯云的云函数在线运行环境中,已经安装了 qcloud\_cos\_v5 对象存储 SDK,而我在本地环境安装的对象存储 SDK 是 qcloud\_cos,为了方便本地调试,这里我设置了一个 debug 开关,来动态导入 qcloud\_cos 依赖,这一点我在之前的系列文章《万物皆可Serverless之使用SCF+COS快速开发全栈应用》中有讲到。

# 配置存储桶appid = '66666666666'secret_id = 'xxxxxxxxxxxxxxx'secret_key = 'xxxxxxxxxxxxxxx'region = 'ap-chongqing'bucket = 'name'+'-'+appid#配置发件邮箱mail_host = "smtp.163.com"mail_user = "xxxxxxxxxx@163.com"mail_pass = "xxxxxxxxxxxxxx"mail_port = 465

然后配置一下自己的邮箱信息和腾讯云对象存储桶信息

配置完成之后,我们再来看一下云函数的入口函数 main_handler(event, context)

def main_handler(event, context):    if 'Time' in event.keys():  # 来自定时触发器        check_send_letters()        return    if 'httpMethod' in event.keys():  # 来自api网关触发器        if event['httpMethod'] == 'GET':            return apiReply('', html=True)  # 返回网页        if event['httpMethod'] == 'POST':  # 添加信件            body = json.loads(event['body'])            flag = addletter(body['date'], body['email'], body['letter'])            return apiReply({                'ok': True if flag else False,                'message': '添加成功' if flag else '添加失败'            })    return apiReply('', html=True)

这里我们根据event的keys里有无'Time'来判断云函数是否是通过定时器来触发的,

这一点我在之前的系列文章《万物皆可 Serverless 之使用 SCF+COS 快速开发全栈应用》中有讲到。

#每天定时检查需要发送的信件def check_send_letters():    loginEmail()    letters = getletters()    for date in letters.keys():        if checkDate(date):            sendEmail(letters[date])

检查云函数是否是通过定时器触发,是因为在后面我们会给这个云函数添加定时触发器来每天定时检查需要发送的信件。

这里的 check\_send\_letters 函数的作用就是登录我们的邮箱并读取在 cos 中的所有信件,然后逐封检查信件的发信日期,如果信件发信日期与当前的日期相符,就会向指定的邮箱发送信件,完成在指定日期投放信件的功能。

if event['httpMethod'] == 'GET':    return apiReply('', html=True)  # 返回网页if event['httpMethod'] == 'POST':  # 添加信件    body = json.loads(event['body'])    flag = addletter(body['date'], body['email'], body['letter'])    return apiReply({         'ok': True if flag else False,         'message': '添加成功' if flag else '添加失败'    })

如果我们的云函数是通过 api 网关触发的话,就判断一下 http 请求的方法是 GET 还是 POST

            给未来的自己写封信        

开始写信

开始写信

送信日期

投递

如果是 GET 请求就返回上面的前端网页,也就是文章开头第一张图,再来瞅一眼

再来看下前端网页的发信过程

function send() {    if (datex.length < 1 || myEmail.value.length < 1 || myLetter.value.length < 1) {        alert('信件内容、送信日期或投递邮箱不能为空');        return;    }    fetch_(window.location.href, {            method: 'POST',            body: JSON.stringify({                date: datex,                email: myEmail.value,                letter: myLetter.value            })        }).then(res => res.json())        .catch(error => console.error('Error:', error))        .then(response => alert(response.ok ? '添加成功:)' : '添加失败:('));}

这里我们是向当前网页地址,也是云函数的 api 网关地址 POST 了一个包含所有信件信息的 json 字符串

if event['httpMethod'] == 'POST':  # 添加信件    body = json.loads(event['body'])    flag = addletter(body['date'], body['email'], body['letter'])    return apiReply({         'ok': True if flag else False,         'message': '添加成功' if flag else '添加失败'    })

回到云函数后端,我们在收到 POST 请求之后,在 event 里拿到 POST 的请求体,并重新将 json 字符串转成 map 对象,之后将 body 传给 addletter 函数,将信件信息保存到 cos 里,然后向网页前端回复信件是否添加成功。

这样整个应用的前后端只用一个云函数就都实现了,是不是很酸爽呀( •̀ ω •́ )y~

第三步:配置云函数触发器

找到本地云函数文件夹下面的 template.yaml 配置文件

Resources:  default:    Type: 'TencentCloud::Serverless::Namespace'    letter:      Properties:        CodeUri: ./        Type: Event        Environment:          Variables:        Description: 给未来写封信云函数        Handler: index.main_handler        MemorySize: 64        Timeout: 3        Runtime: Python3.6        Events:          timer:            Type: Timer            Properties:              CronExpression: '0 0 8 * * * *'              Enable: True          letter_apigw:            Type: APIGW            Properties:              StageName: release              ServiceId:              HttpMethod: ANY      Type: 'TencentCloud::Serverless::Function'

这里主要配置了一下云函数的名称,timer 触发器和 api 网关触发器,可以自行设置。

第四步:上线发布云函数,api 网关启用响应集成

第五步:绑定备案域名

上述就是小编为大家分享的如何基于Serverless使用 SCF+COS 给未来写封信了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注行业资讯频道。

0