亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何基于Serverless使用云函數SCF+COS免費運營微信公眾號

發布時間:2021-10-12 14:03:30 來源:億速云 閱讀:153 作者:柒染 欄目:云計算

這篇文章將為大家詳細講解有關如何基于Serverless使用云函數SCF+COS免費運營微信公眾號,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

是的,你沒聽錯,這一次我來帶大家直接上手運營微信公眾號。

效果展示

如何基于Serverless使用云函數SCF+COS免費運營微信公眾號

如何基于Serverless使用云函數SCF+COS免費運營微信公眾號

操作步驟

在上一篇《萬物皆可Serverless之使用SCF+COS快速開發全棧應用》教程中,

我們用騰訊云無服務器云函數 SCF 和對象存儲實現了一個后端云函數,這個云函數可以根據我們的請求返回對應的結果。

現在我們將嘗試在這個云函數的基礎上解析微信 XML 消息,實現公眾號消息的自動回復,關鍵詞回復,文字菜單等功能。

第一步:添加相關依賴

為了快速完成開發,這里我們選擇 python 第三方開源庫 wechatpy 來接入微信公眾平臺。

如何基于Serverless使用云函數SCF+COS免費運營微信公眾號

wechatpy 支持以下功能

  1. 普通公眾平臺被動響應和主動調用 API

  2. 企業微信 API

  3. 微信支付 API

  4. 第三方平臺代公眾號調用接口 API

  5. 小程序云開發 API

可見功能是十分完整的,不僅支持普通公眾平臺主被動調用,企業微信和微信支付,甚至還支持第三方平臺代公眾號調用接口,拿來運營微信公眾號是十分綽綽有余的~

如何基于Serverless使用云函數SCF+COS免費運營微信公眾號

由于騰訊云函數的運行環境中缺少第三方庫,需要我們自己手動上傳添加依賴,這里我們需要添加的第三方依賴有:wechatpyotionaldictxmltodict 以及 timeout\_decorator

其中 wechatpy 需要依賴 otionaldictxmltodicttimeout\_decorator 是用來限制函數運行時長的,具體的依賴文件可以自行 pip 安裝后 copy 到云函數項目根目錄,如上圖。

第二步:接入微信公眾號

如何基于Serverless使用云函數SCF+COS免費運營微信公眾號

這里需要記下自己的 AppID、Token 和 EncodingAESKey,消息加密方式建議選為安全模式。這個頁面先不要關,一會兒上線發布好云函數還需要過來再次修改配置。

第三步:編寫云函數解析并回復微信公眾號消息

這一步可以直接參考 wechatpy 的官方文檔

如何基于Serverless使用云函數SCF+COS免費運營微信公眾號

Life is short, show me the code.

這里我就直接上代碼了(原始業務代碼已略去,可以按照自己的需求開發)

import json
import timeout_decorator
from wechatpy.replies import ArticlesReply
from wechatpy.utils import check_signature
from wechatpy.crypto import WeChatCrypto
from wechatpy import parse_message, create_reply
from wechatpy.exceptions import InvalidSignatureException, InvalidAppIdException

# 是否開啟本地debug模式
debug = False

# 騰訊云對象存儲依賴
if debug:
    from qcloud_cos import CosConfig
    from qcloud_cos import CosS3Client
    from qcloud_cos import CosServiceError
    from qcloud_cos import CosClientError
else:
    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 = u'xxxxxxxxxxxxxxx'
secret_key = u'xxxxxxxxxxxxxxx'
region = u'ap-chongqing'
bucket = 'name'+'-'+appid

# 對象存儲實例
config = CosConfig(Secret_id=secret_id, Secret_key=secret_key, Region=region)
client = CosS3Client(config)

# 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 getReplys():
    replyMap = {}
    replyTxt = cosRead('Replys.txt')  # 讀取數據
    if len(replyTxt) > 0:
        replyMap = json.loads(replyTxt)
    return replyMap

def addReplys(reply):
    replyMap = getReplys()
    if len(replyMap) > 0:
        replyMap[reply]='我是黑名單'
    return cosWrite('Replys.txt', json.dumps(replyMap, ensure_ascii=False)) if len(replyMap) > 0 else False


def delReplys(reply):
    replyMap = getReplys()
    if len(replyMap) > 0:
        replyMap.pop(reply)
    return cosWrite('Replys.txt', json.dumps(replyMap, ensure_ascii=False)) if len(replyMap) > 0 else False


# 微信公眾號對接
wecaht_id = 'xxxxxxxxxxxxxxx'
WECHAT_TOKEN = 'xxxxxxxxxxxxxxxxxxx'
encoding_aes_key = 'xxxxxxxxxxxxxxxxxxxxxx'

crypto = WeChatCrypto(WECHAT_TOKEN, encoding_aes_key, wecaht_id)

# api網關響應集成
def apiReply(reply, txt=False, content_type='application/json', code=200):
    return {
        "isBase64Encoded": False,
        "statusCode": code,
        "headers": {'Content-Type': content_type},
        "body": json.dumps(reply, ensure_ascii=False) if not txt else str(reply)
    }

def replyMessage(msg):
    txt = msg.content
    ip = msg.source
    print('請求信息--->'+ip+'%'+txt)  # 用來在騰訊云控制臺打印請求日志
    replysTxtMap = getReplys() # 獲取回復關鍵詞
    if '@' in txt:
        keys = txt.split('@')
        if keys[0] == '電影': #do something
            return
        if keys[0] == '音樂': #do something
            return
        if keys[0] == '下架': #do something
            return
        if keys[0] == '上架': #do something
            return
        if keys[0] == '回復': #do something
            return
        if keys[0] == '刪除': #do something
            return
    elif txt in replysTxtMap.keys(): # 如果消息在回復關鍵詞內則自動回復
        return create_reply(replysTxtMap[txt], msg)
    return create_reply("喵嗚 ?'ω'?", msg)

def wechat(httpMethod, requestParameters, body=''):
    if httpMethod == 'GET':
        signature = requestParameters['signature']
        timestamp = requestParameters['timestamp']
        nonce = requestParameters['nonce']
        echo_str = requestParameters['echostr']
        try:
            check_signature(WECHAT_TOKEN, signature, timestamp, nonce)
        except InvalidSignatureException:
            echo_str = 'error'
        return apiReply(echo_str, txt=True, content_type="text/plain")
    elif httpMethod == 'POST':
        msg_signature = requestParameters['msg_signature']
        timestamp = requestParameters['timestamp']
        nonce = requestParameters['nonce']
        try:
            decrypted_xml = crypto.decrypt_message(
                body,
                msg_signature,
                timestamp,
                nonce
            )
        except (InvalidAppIdException, InvalidSignatureException):
            return
        msg = parse_message(decrypted_xml)
        if msg.type == 'text':
            reply = replyMessage(msg)
        elif msg.type == 'image':
            reply = create_reply('哈? ???\n好端端的,給我發圖片干啥~', msg)
        elif msg.type == 'voice':
            reply = create_reply('哈? ???\n好端端的,給我發語音干啥~', msg)
        else:
            reply = create_reply('哈? ???\n搞不明白你給我發了啥~', msg)
        reply = reply.render()
        print('返回結果--->'+str(reply))  # 用來在騰訊云控制臺打印請求日志
        reply = crypto.encrypt_message(reply, nonce, timestamp)
        return apiReply(reply, txt=True, content_type="application/xml")
    else:
        msg = parse_message(body)
        reply = create_reply("喵嗚 ?'ω'?", msg)
        reply = reply.render()
        print('返回結果--->'+str(reply))  # 用來在騰訊云控制臺打印請求日志
        reply = crypto.encrypt_message(reply, nonce, timestamp)
        return apiReply(reply, txt=True, content_type="application/xml")


@timeout_decorator.timeout(4, timeout_exception=StopIteration)
def myMain(httpMethod, requestParameters, body=''):
    return wechat(httpMethod, requestParameters, body=body)


def timeOutReply(httpMethod, requestParameters, body=''):
    msg_signature = requestParameters['msg_signature']
    timestamp = requestParameters['timestamp']
    nonce = requestParameters['nonce']
    try:
        decrypted_xml = crypto.decrypt_message(
            body,
            msg_signature,
            timestamp,
            nonce
        )
    except (InvalidAppIdException, InvalidSignatureException):
        return
    msg = parse_message(decrypted_xml)
    reply = create_reply("出了點小問題,請稍后再試", msg).render()
    print('返回結果--->'+str(reply))  # 用來在騰訊云控制臺打印請求日志
    reply = crypto.encrypt_message(reply, nonce, timestamp)
    return apiReply(reply, txt=True, content_type="application/xml")


def main_handler(event, context):
    body = ''
    httpMethod = event["httpMethod"]
    requestParameters = event['queryString']
    if 'body' in event.keys():
        body = event['body']
    try:
        response = myMain(httpMethod, requestParameters, body=body)
    except:
        response = timeOutReply(httpMethod, requestParameters, body=body)
    return response

請求參數解析和COS讀寫部分可參考上一篇《萬物皆可 Serverless 之使用 SCF+COS 快速開發全棧應用》教程

下面我來捋一下整個云函數的思路

def main_handler(event, context):
    body = ''
    httpMethod = event["httpMethod"]
    requestParameters = event['queryString']
    if 'body' in event.keys():
        body = event['body']
    try:
        response = myMain(httpMethod, requestParameters, body=body)
    except:
        response = timeOutReply(httpMethod, requestParameters, body=body)
    return response

我們先從 main\_handler 入手,

這里我們通過 API 網關觸發云函數在 event 里拿到了微信公眾號請求的方法、頭部和請求體,然后傳給 myMain 函數做處理,需要注意的是 myMain 是通過 timeout\_decorator 包裝的限時運行函數。

@timeout_decorator.timeout(4, timeout_exception=StopIteration)
def myMain(httpMethod, requestParameters, body=''):
    return wechat(httpMethod, requestParameters, body=body)

當 myMain 函數運行市場超過設定的 4 秒后,就會拋出異常,

然后我們可以通過設置一個 timeOutReply 函數來處理超時后的微信公眾號消息回復,可是為什么要這么做呢?

如何基于Serverless使用云函數SCF+COS免費運營微信公眾號

可以看到,當云函數運行超時后,微信這邊就會顯示「該公眾號提供的服務器出現故障,請稍后再試」

這對用戶體驗是極不友好的,所以我們需要一個函數超時后的回復來兜底。

如何基于Serverless使用云函數SCF+COS免費運營微信公眾號

那么對于一次微信公眾號后臺消息請求多長時間算是超時呢?答案是 5 秒左右,從云函數后臺的調用日志我們可以得到這個結果。

不過需要注意的是對于用戶的一次消息請求,微信可能會每隔 1 秒左右重撥一次請求,直到收到服務器第一次響應。另外,超過 3 次應該就不會再重撥了,并且在 5 秒超時后即使云函數調用成功并返回了數據,用戶也不會再接收到消息了~

所以我們就很有必要將自己的云函數的運行時長限制在 5 秒之內了!

當然只通過配置云函數超時時長得方式來處理是不正確的,因為這樣做云函數超時后就被系統停掉了,并不會向微信返回消息。所以從一開始我就導入了 timeout\_decorator 庫來限制主函數的運行時長,并用一個超時后回復函數來兜底。

另外值得一提的是,在我原始的業務代碼中是有一些爬蟲,這些爬蟲本來我是單線程順序執行的,考慮到超時問題,我在微信云函數版這里全部改成了多線程運行來壓縮時間,所以如果你也有一些比較耗時的小任務話,也可以嘗試通過多線程的方式來壓縮云函數的運行時長。

我們接著向下看:

def wechat(httpMethod, requestParameters, body=''):
    if httpMethod == 'GET':
        signature = requestParameters['signature']
        timestamp = requestParameters['timestamp']
        nonce = requestParameters['nonce']
        echo_str = requestParameters['echostr']
        try:
            check_signature(WECHAT_TOKEN, signature, timestamp, nonce)
        except InvalidSignatureException:
            echo_str = 'error'
        return apiReply(echo_str, txt=True, content_type="text/plain")
    elif httpMethod == 'POST':
        msg_signature = requestParameters['msg_signature']
        timestamp = requestParameters['timestamp']
        nonce = requestParameters['nonce']
        try:
            decrypted_xml = crypto.decrypt_message(
                body,
                msg_signature,
                timestamp,
                nonce
            )
        except (InvalidAppIdException, InvalidSignatureException):
            return
        msg = parse_message(decrypted_xml)
        if msg.type == 'text':
            reply = replyMessage(msg)
        elif msg.type == 'image':
            reply = create_reply('哈? ???\n好端端的,給我發圖片干啥~', msg)
        elif msg.type == 'voice':
            reply = create_reply('哈? ???\n好端端的,給我發語音干啥~', msg)
        else:
            reply = create_reply('哈? ???\n搞不明白你給我發了啥~', msg)
        reply = reply.render()
        print('返回結果--->'+str(reply))  # 用來在騰訊云控制臺打印請求日志
        reply = crypto.encrypt_message(reply, nonce, timestamp)
        return apiReply(reply, txt=True, content_type="application/xml")
    else:
        msg = parse_message(body)
        reply = create_reply("喵嗚 ?'ω'?", msg)
        reply = reply.render()
        print('返回結果--->'+str(reply))  # 用來在騰訊云控制臺打印請求日志
        reply = crypto.encrypt_message(reply, nonce, timestamp)
        return apiReply(reply, txt=True, content_type="application/xml")

這里的 wechat 函數就是整個微信消息的解析過程,首先判斷請求方法是 GET 還是 POST,GET 方法只在第一次綁定微信后臺時會用到,這時我們會從微信服務器推送的請求參數中拿到 signature, timestamp, echostrnonce 參數,

check_signature(WECHAT_TOKEN, signature, timestamp, nonce)

我們只需根據自己的公眾號 token 和來生成簽名與微信服務器傳過來的 signature 對比看是否一致,若一致就說明我們的消息加解密驗證是OK的,然后再將 echostr 原樣返回即可接入微信公眾號后臺。

接入好微信公眾號后,如果有用戶在后臺給我們發送消息,這里云函數收到的就是 POST 方法,

elif httpMethod == 'POST':
        msg_signature = requestParameters['msg_signature']
        timestamp = requestParameters['timestamp']
        nonce = requestParameters['nonce']
        try:
            decrypted_xml = crypto.decrypt_message(
                body,
                msg_signature,
                timestamp,
                nonce
            )
        except (InvalidAppIdException, InvalidSignatureException):
            return
        msg = parse_message(decrypted_xml)
        if msg.type == 'text':
            reply = replyMessage(msg)
        elif msg.type == 'image':
            reply = create_reply('哈? ???\n好端端的,給我發圖片干啥~', msg)
        elif msg.type == 'voice':
            reply = create_reply('哈? ???\n好端端的,給我發語音干啥~', msg)
        else:
            reply = create_reply('哈? ???\n搞不明白你給我發了啥~', msg)
        reply = reply.render()
        print('返回結果--->'+str(reply))  # 用來在騰訊云控制臺打印請求日志
        reply = crypto.encrypt_message(reply, nonce, timestamp)
        return apiReply(reply, txt=True, content_type="application/xml")

然后我們根據前面在微信公眾號后臺拿到的 id,token 和 aes 加密 key 來初始化消息加解密實例并解密還原用戶發送的消息

# 微信公眾號對接
wecaht_id = 'xxxxxxxxxxxxxxx'
WECHAT_TOKEN = 'xxxxxxxxxxxxxxxxxxx'
encoding_aes_key = 'xxxxxxxxxxxxxxxxxxxxxx'

crypto = WeChatCrypto(WECHAT_TOKEN, encoding_aes_key, wecaht_id)

接著判斷一下消息類型,不同類型的消息可自行處理

        msg = parse_message(decrypted_xml)
        if msg.type == 'text':
            reply = replyMessage(msg)
        elif msg.type == 'image':
            reply = create_reply('哈? ??? 好端端的,給我發圖片干啥~', msg)
        elif msg.type == 'voice':
            reply = create_reply('哈? ??? 好端端的,給我發語音干啥~', msg)
        else:
            reply = create_reply('哈? ??? 搞不明白你給我發了啥~', msg)

需要注意的是當一個用戶新關注自己的公眾號時,我們收到的是一個其他類型的消息,也就是上面的最后一個判斷項,這里你可以自己設置新關注用戶的歡迎語

        reply = create_reply('哈? ???\n搞不明白你給我發了啥~', msg)
        reply = reply.render()
        print('返回結果--->'+str(reply))  # 用來在騰訊云控制臺打印請求日志
        reply = crypto.encrypt_message(reply, nonce, timestamp)
        return apiReply(reply, txt=True, content_type="application/xml")

之后我們通過 create\_reply 來快速創建一個文本回復,并通過 render() 來生成 xml 回復消息文本。因為我之前在后臺設置的是安全模式,所以還需要把 xml 重新通過 crypto.encrypt\_message 方法加密,然后才能把加密后的回復消息返回給微信服務器。

上一篇文章我有提到我們不能直接返回消息,需要按照特定的格式返回數據(API 網關需要開啟響應集成)

# api網關響應集成
def apiReply(reply, txt=False, content_type='application/json', code=200):
    return {
        "isBase64Encoded": False,
        "statusCode": code,
        "headers": {'Content-Type': content_type},
        "body": json.dumps(reply, ensure_ascii=False) if not txt else str(reply)
    }

第四步:上線發布云函數、添加 API 網關觸發器、啟用響應集成

參考上一篇教程 《萬物皆可 Serverless 之使用 SCF+COS 快速開發全棧應用》

第五步:修改微信公眾號后臺服務器配置

終于到最后一步了,如果你已經上線發布了好自己的云函數,那么快去微信公眾號后臺綁定一下自己的后臺服務器配置吧~

如何基于Serverless使用云函數SCF+COS免費運營微信公眾號

呼~ 大功告成

關于如何基于Serverless使用云函數SCF+COS免費運營微信公眾號就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

漠河县| 田东县| 赣榆县| 济南市| 东源县| 焦作市| 襄城县| 西城区| 通江县| 汾阳市| 叶城县| 沙洋县| 都江堰市| 兴仁县| 方正县| 崇州市| 黄平县| 灵石县| 凤台县| 波密县| 龙胜| 维西| 河曲县| 琼中| 吐鲁番市| 调兵山市| 包头市| 新绛县| 喜德县| 湖州市| 奈曼旗| 罗平县| 信丰县| 滁州市| 西宁市| 民县| 江源县| 启东市| 富源县| 始兴县| 左云县|