欧美三级国产三级日韩三级_亚洲熟妇丰满大屁股熟妇_欧美亚洲成人一区二区三区_国产精品久久久久久模特

使用云函數(shù)SCF+COS免費(fèi)運(yùn)營微信公眾號(hào) - 新聞資訊 - 云南小程序開發(fā)|云南軟件開發(fā)|云南網(wǎng)站建設(shè)-昆明葵宇信息科技有限公司

159-8711-8523

云南網(wǎng)建設(shè)/小程序開發(fā)/軟件開發(fā)

知識(shí)

不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價(jià)值,我們在追求其視覺表現(xiàn)的同時(shí),更側(cè)重于功能的便捷,營銷的便利,運(yùn)營的高效,讓網(wǎng)站成為營銷工具,讓軟件能切實(shí)提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序?yàn)楹笃谏?jí)提供便捷的支持!

您當(dāng)前位置>首頁 » 新聞資訊 » 公眾號(hào)相關(guān) >

使用云函數(shù)SCF+COS免費(fèi)運(yùn)營微信公眾號(hào)

發(fā)表時(shí)間:2020-9-30

發(fā)布人:葵宇科技

瀏覽次數(shù):78

是的,你沒聽錯(cuò),這一次我來帶大家直接上手運(yùn)營微信公眾號(hào)。

震驚,Awesome,哼,我才不信捏,所謂無圖無真相 ~

效果展示

更多的體驗(yàn),可以關(guān)注我的微信公眾號(hào):乂乂又又 (僅供測試,不要亂搞哈~)

嗯,這次我信了,快點(diǎn)教一下我吧,嚶嚶嚶~

操作步驟

在上一篇《使用SCF+COS快速開發(fā)全棧應(yīng)用》教程中,我們用騰訊云無服務(wù)器云函數(shù) SCF 和對(duì)象存儲(chǔ) COS 實(shí)現(xiàn)了一個(gè)后端云函數(shù),這個(gè)云函數(shù)可以根據(jù)我們的請(qǐng)求返回對(duì)應(yīng)的結(jié)果。

現(xiàn)在我們將嘗試在這個(gè)云函數(shù)的基礎(chǔ)上解析微信 XML 消息,實(shí)現(xiàn)公眾號(hào)消息的自動(dòng)回復(fù),關(guān)鍵詞回復(fù),文字菜單等功能。

01

添加相關(guān)依賴

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

wechatpy 支持以下功能:

  1. 普通公眾平臺(tái)被動(dòng)響應(yīng)和主動(dòng)調(diào)用 API

  2. 企業(yè)微信 API

  3. 微信支付 API

  4. 第三方平臺(tái)代公眾號(hào)調(diào)用接口 API

  5. 小程序云開發(fā) API

可見功能是十分完整的,不僅支持普通公眾平臺(tái)主被動(dòng)調(diào)用,企業(yè)微信和微信支付,甚至還支持第三方平臺(tái)代公眾號(hào)調(diào)用接口,拿來運(yùn)營微信公眾號(hào)是十分綽綽有余的~

由于騰訊云函數(shù)的運(yùn)行環(huán)境中缺少第三方庫,需要我們自己手動(dòng)上傳添加依賴,這里我們需要添加的第三方依賴有:wechatpy、optionaldict、xmltodict 以及 timeout_decorator

其中 wechatpy 需要依賴 optionaldict、xmltodicttimeout_decorator 是用來限制函數(shù)運(yùn)行時(shí)長的,具體的依賴文件可以自行 pip 安裝后 copy 到云函數(shù)項(xiàng)目根目錄,如上圖。

02

接入微信公眾號(hào)

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

03

編寫云函數(shù)解析并回復(fù)微信公眾號(hào)消息

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

地址:http://docs.wechatpy.org/zh_CN/master/quickstart.html#id2

Life is short, show me the code.

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

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


# 騰訊云對(duì)象存儲(chǔ)依賴
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


# 配置存儲(chǔ)桶
appid = '66666666666'
secret_id = u'xxxxxxxxxxxxxxx'
secret_key = u'xxxxxxxxxxxxxxx'
region = u'ap-chongqing'
bucket = 'name'+'-'+appid


# 對(duì)象存儲(chǔ)實(shí)例
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')  # 讀取數(shù)據(jù)
    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




# 微信公眾號(hào)對(duì)接
wecaht_id = 'xxxxxxxxxxxxxxx'
WECHAT_TOKEN = 'xxxxxxxxxxxxxxxxxxx'
encoding_aes_key = 'xxxxxxxxxxxxxxxxxxxxxx'


crypto = WeChatCrypto(WECHAT_TOKEN, encoding_aes_key, wecaht_id)


# api網(wǎng)關(guān)響應(yīng)集成
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('請(qǐng)求信息--->'+ip+'%'+txt)  # 用來在騰訊云控制臺(tái)打印請(qǐng)求日志
    replysTxtMap = getReplys() # 獲取回復(fù)關(guān)鍵詞
    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] == '回復(fù)': #do something
            return
        if keys[0] == '刪除': #do something
            return
    elif txt in replysTxtMap.keys(): # 如果消息在回復(fù)關(guān)鍵詞內(nèi)則自動(dòng)回復(fù)
        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好端端的,給我發(fā)圖片干啥~', msg)
        elif msg.type == 'voice':
            reply = create_reply('哈? ???\n好端端的,給我發(fā)語音干啥~', msg)
        else:
            reply = create_reply('哈? ???\n搞不明白你給我發(fā)了啥~', msg)
        reply = reply.render()
        print('返回結(jié)果--->'+str(reply))  # 用來在騰訊云控制臺(tái)打印請(qǐng)求日志
        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('返回結(jié)果--->'+str(reply))  # 用來在騰訊云控制臺(tái)打印請(qǐng)求日志
        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("出了點(diǎn)小問題,請(qǐng)稍后再試", msg).render()
    print('返回結(jié)果--->'+str(reply))  # 用來在騰訊云控制臺(tái)打印請(qǐng)求日志
    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

請(qǐng)求參數(shù)解析和 COS 讀寫部分可參考上一篇《使用 SCF+COS 快速開發(fā)全棧應(yīng)用》教程

下面我來捋一下整個(gè)云函數(shù)的思路

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 網(wǎng)關(guān)觸發(fā)云函數(shù)在 event 里拿到了微信公眾號(hào)請(qǐng)求的方法、頭部和請(qǐng)求體,然后傳給 myMain 函數(shù)做處理,需要注意的是 myMain 是通過timeout_decorator包裝的限時(shí)運(yùn)行函數(shù)。

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

當(dāng) myMain 函數(shù)運(yùn)行市場超過設(shè)定的 4 秒后,就會(huì)拋出異常。

然后我們可以通過設(shè)置一個(gè) timeOutReply 函數(shù)來處理超時(shí)后的微信公眾號(hào)消息回復(fù),可是為什么要這么做呢?

可以看到,當(dāng)云函數(shù)運(yùn)行超時(shí)后,微信這邊就會(huì)顯示「該公眾號(hào)提供的服務(wù)器出現(xiàn)故障,請(qǐng)稍后再試」

這對(duì)用戶體驗(yàn)是極不友好的,所以我們需要一個(gè)函數(shù)超時(shí)后的回復(fù)來兜底。

那么對(duì)于一次微信公眾號(hào)后臺(tái)消息請(qǐng)求多長時(shí)間算是超時(shí)呢?答案是 5 秒左右,從云函數(shù)后臺(tái)的調(diào)用日志我們可以得到這個(gè)結(jié)果。

不過需要注意的是對(duì)于用戶的一次消息請(qǐng)求,微信可能會(huì)每隔 1 秒左右重?fù)芤淮握?qǐng)求,直到收到服務(wù)器第一次響應(yīng)。另外,超過 3 次應(yīng)該就不會(huì)再重?fù)芰?#xff0c;并且在 5 秒超時(shí)后即使云函數(shù)調(diào)用成功并返回了數(shù)據(jù),用戶也不會(huì)再接收到消息了~

所以我們就很有必要將自己的云函數(shù)的運(yùn)行時(shí)長限制在 5 秒之內(nèi)了!

當(dāng)然只通過配置云函數(shù)超時(shí)時(shí)長得方式來處理是不正確的,因?yàn)檫@樣做云函數(shù)超時(shí)后就被系統(tǒng)停掉了,并不會(huì)向微信返回消息。所以從一開始我就導(dǎo)入了 timeout_decorator 庫來限制主函數(shù)的運(yùn)行時(shí)長,并用一個(gè)超時(shí)后回復(fù)函數(shù)來兜底。

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

我們接著向下看:

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好端端的,給我發(fā)圖片干啥~', msg)
        elif msg.type == 'voice':
            reply = create_reply('哈? ???\n好端端的,給我發(fā)語音干啥~', msg)
        else:
            reply = create_reply('哈? ???\n搞不明白你給我發(fā)了啥~', msg)
        reply = reply.render()
        print('返回結(jié)果--->'+str(reply))  # 用來在騰訊云控制臺(tái)打印請(qǐng)求日志
        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('返回結(jié)果--->'+str(reply))  # 用來在騰訊云控制臺(tái)打印請(qǐng)求日志
        reply = crypto.encrypt_message(reply, nonce, timestamp)
        return apiReply(reply, txt=True, content_type="application/xml")

這里的 wechat 函數(shù)就是整個(gè)微信消息的解析過程,首先判斷請(qǐng)求方法是 GET 還是 POST,GET 方法只在第一次綁定微信后臺(tái)時(shí)會(huì)用到,這時(shí)我們會(huì)從微信服務(wù)器推送的請(qǐng)求參數(shù)中拿到 signature, timestamp, echostrnonce 參數(shù),

check_signature(WECHAT_TOKEN, signature, timestamp, nonce)

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

接入好微信公眾號(hào)后,如果有用戶在后臺(tái)給我們發(fā)送消息,這里云函數(shù)收到的就是 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好端端的,給我發(fā)圖片干啥~', msg)
        elif msg.type == 'voice':
            reply = create_reply('哈? ???\n好端端的,給我發(fā)語音干啥~', msg)
        else:
            reply = create_reply('哈? ???\n搞不明白你給我發(fā)了啥~', msg)
        reply = reply.render()
        print('返回結(jié)果--->'+str(reply))  # 用來在騰訊云控制臺(tái)打印請(qǐng)求日志
        reply = crypto.encrypt_message(reply, nonce, timestamp)
        return apiReply(reply, txt=True, content_type="application/xml")

然后我們根據(jù)前面在微信公眾號(hào)后臺(tái)拿到的 id,token 和 aes 加密 key 來初始化消息加解密實(shí)例并解密還原用戶發(fā)送的消息

# 微信公眾號(hào)對(duì)接
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('哈? ??? 好端端的,給我發(fā)圖片干啥~', msg)
        elif msg.type == 'voice':
            reply = create_reply('哈? ??? 好端端的,給我發(fā)語音干啥~', msg)
        else:
            reply = create_reply('哈? ??? 搞不明白你給我發(fā)了啥~', msg)

需要注意的是當(dāng)一個(gè)用戶新關(guān)注自己的公眾號(hào)時(shí),我們收到的是一個(gè)其他類型的消息,也就是上面的最后一個(gè)判斷項(xiàng),這里你可以自己設(shè)置新關(guān)注用戶的歡迎語

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

之后我們通過 create_reply 來快速創(chuàng)建一個(gè)文本回復(fù),并通過 render() 來生成 xml 回復(fù)消息文本。因?yàn)槲抑霸诤笈_(tái)設(shè)置的是安全模式,所以還需要把 xml 重新通過 crypto.encrypt_message 方法加密,然后才能把加密后的回復(fù)消息返回給微信服務(wù)器。

上一篇文章我有提到我們不能直接返回消息,需要按照特定的格式返回?cái)?shù)據(jù)(API 網(wǎng)關(guān)需要開啟響應(yīng)集成)

# api網(wǎng)關(guān)響應(yīng)集成
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)
    }

04

上線發(fā)布云函數(shù)、添加 API 網(wǎng)關(guān)觸發(fā)器、啟用響應(yīng)集成

參考上一篇教程 《使用 SCF+COS 快速開發(fā)全棧應(yīng)用》

05

修改微信公眾號(hào)后臺(tái)服務(wù)器配置

終于到最后一步了,如果你已經(jīng)上線發(fā)布了好自己的云函數(shù),那么快去微信公眾號(hào)后臺(tái)綁定一下自己的后臺(tái)服務(wù)器配置吧~

呼~ 大功告成

點(diǎn)擊閱讀原文,領(lǐng)取 COS 限時(shí)1元禮包!

相關(guān)案例查看更多