前後端分離djangorestframework—— 接入微信模板消息推送

来源:https://www.cnblogs.com/yangva/archive/2019/03/13/10517455.html
-Advertisement-
Play Games

微信 什麼是微信也不多說,跟前面的支付寶一樣的 微信支付 微信支付也有個沙箱環境,沙箱環境官方文檔 由文檔中那句很顯眼的話所得,即使是測試環境也需要真實的商戶號,所以這個就沒法想支付寶那樣用沙箱賬號來演示了。至於為什麼沒有沙箱賬號這就不得而知了,想接入微信支付商戶的朋友,請移步先註... ...


微信

什麼是微信也不多說,跟前面的支付寶一樣的

微信支付

微信支付也有個沙箱環境,沙箱環境官方文檔  

 

由文檔中那句很顯眼的話所得,即使是測試環境也需要真實的商戶號,所以這個就沒法想支付寶那樣用沙箱賬號來演示了。至於為什麼沒有沙箱賬號這就不得而知了,想接入微信支付商戶的朋友,請移步先註冊為商戶,上傳相關資料審核後方可使用:傳送門 

 

所以關於微信支付,由於這些種種限制,就不去註冊商戶了,所以支付方面本文在此略過,感興趣的朋友自己去研究了,我看微信的文檔也很淺顯易懂的 

 

微信模板消息推送

 

因為微信的模板消息推送改版,現在需要認證的微信企業號才能玩,所以目前來說我們只能使用微信給的沙箱測試平臺了,傳送門 

用你的微信登錄,之後會給我們自動生成一個id 和key:

還有一個測試的可用公眾賬號:

 

接著按微信官方給的文檔:模板消息推送

 

其實大概的流程就是這樣:

 

 

 

 

1.預設情況下,用戶的微信只和微信服務端有聯繫,且微信服務端里有用戶的唯一ID,而我們的平臺的目標是要通過公眾號給用戶發消息

2.但是預設用戶的微信和我們平臺的微信不相通的,如隔了一道牆

3.我們給用戶一個頁面,頁面上有我們的二維碼,讓用戶掃碼關註我們的公眾號

4.在第3步操作也是通過微信的服務端作為中間人完成的,且當用戶關註成功的同時,微信服務端會把用戶ID自動回傳(或者說回調)給我們平臺的公眾號

5.拿到用戶ID之後,我們的微信公眾號就可以給用戶推送消息了

 

其實步驟是挺簡單的,上面5步中,其實實際的業務邏輯只有第3,第4和第5三個步驟,且這幾個步驟里每個的請求url都需要通過微信服務端來完成,所以還需要再看下微信的官方文檔給我們解說的

 

 

前期準備:

 

1,修改地址:

還是剛纔那個申請測試賬號頁面,滑動下麵,找到網頁賬號這裡,點修改

 

看到的提示,寫得很清楚,我這裡只是作為測試而已,這個地址不能是127.0.0.1換回地址了,至少得是區域網地址,因為一會兒用手機微信測試時需要調用這個地址,所以你的手機得和電腦是同一個區域網段,當然真實的使用時是公網的地址

 

 

 

 

 點擊確認之後,顯示通過安全檢測的話就配置成功了

 

 

2.還要創建一個模板,獲取一個模板id

點新增測試模板:添加模板時註意格式,比如下麵的{{first.DATA}},這個【.DATA】才是我們需要添加的數據,其他都不是,就好比Python中的字元串格式化一樣,做類比理解就很能懂了

 

按照文檔給的提示操作就行,提交之後如下,所以你如果填錯了,只能刪除重新添加,不能修改

 

 

3.作為接收信息的用戶微信號必須關註測試賬號:

 4.如果有需要的話,設置js的sdk url

當然是要調用微信的sdk時才會用到這個

 

代碼實現

 

前面的準備工作准備好之後,開始寫代碼 

 

不過,先通過微信的文檔,得知我們此時需要用的url:

 

 

1.綁定url:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

 

相關參數:

參數

必須

說明

appid

公眾號的唯一標識(這個就是我們前面申請的)

redirect_uri

授權後重定向的回調鏈接地址(我們前面申請的)

response_type

返回類型,請填寫code

scope

應用授權作用域,snsapi_base (不彈出授權頁面,直接跳轉,只能獲取用戶openid),snsapi_userinfo (彈出授權頁面,可通過openid拿到昵稱、性別、所在地。並且,即使在未關註的情況下,只要用戶授權,也能獲取其信息)

state

重定向後會帶上state參數,開發者可以填寫a-zA-Z0-9的參數值,最多128位元組,該值會被微信原樣返回,我們可以將其進行比對,防止別人的攻擊。

#wechat_redirect

直接在微信打開鏈接,可以不填此參數。做頁面302重定向時候,必須帶此參數

 

 

 

 2.獲取token的url

https://api.weixin.qq.com/sns/oauth2/access_token

相關參數:

appid

您的測試id號

secret

您的測試id的secret

code

微信自動回傳的參數,用request.GET.get("code")獲取

grant_type

authorization_code

 

 

3.發送模板消息的介面

https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN

 

 

 

4.發送非模板,正文消息的url

https://api.weixin.qq.com/cgi-bin/message/custom/send

相關參數跟模板消息的參數一樣

 

真正的代碼實現

好的,開始碼代碼,乾!

 

創建一個名為WachatTest的django項目,app名就是app:

 

 然後因為要生成二維碼,此處運用了qrcode.js的第三方js庫   文件下載:點我

 

根目錄創建static目錄,存放如下文件,wx.jpg就是剛纔那個測試微信公眾號的圖片,我把它下載下來並更名為wx.jpg了

 

 

url:

 

html:

settings:

 還是配置文件部分,如果你啟動項目時提示ALLOW_HOSTS之類的錯誤,作如下更改:

views:

與模板相關的配置,註意與之前創建的模板對應

 

model,db_index=True的意思是自動在數據創建索引的意思

 

運行項目之前記得遷移資料庫,並寫入幾個數據作為測試

 

啟動項目,登錄再關註,不多說

 

 登錄成功之後,綁定頁面,點擊按鈕之後,把這個測試的公眾號二維碼圖片轉成了帶有一些參數的url,然後qrcode把這個帶有參數的url轉成了二維碼:

 

我用一個微信號測試掃碼之後(前提必須先關註那個微信公眾測試號才能授權),點擊允許

 

 

然後會跳轉到這個界面,表示成功授權

 

 

現在再做最終的模板消息發送,訪問/sendmsg:

 

 

查看手機端信息,得到的信息正好是我們之前設置的

 

 

大概的流程就走完了,因為我只是測試,沒有做得多麼高大上,其實比如那個模板消息,可以根據不同的用戶發不同的數據,或者這段數據直接搞一個form表單,讓非開發人員也可以使用它,點擊發送就行了,還有上面說的那個當前用戶的問題,只給當前用戶發,不給沒有操作的人發,或者定向群發啥啥的,反正主要的開發邏輯就這些,其他的隨便玩,玩出花來都可以

 

 

微信官方的全部流程:傳送門

 

相關的代碼:

import hashlib
from django.db import models


class UserInfo(models.Model):
    username = models.CharField("用戶名", max_length=64, unique=True)
    password = models.CharField("密碼", max_length=64)
    uid = models.CharField(verbose_name='個人唯一ID', max_length=64, unique=True)
    wx_id = models.CharField(verbose_name="微信ID", max_length=128, blank=True, null=True, db_index=True)

    def save(self, *args, **kwargs):
        # 創建用戶時,為用戶自動生成個人唯一ID
        if not self.pk:
            m = hashlib.md5()
            m.update(self.username.encode(encoding="utf-8"))
            self.uid = m.hexdigest()
        super(UserInfo, self).save(*args, **kwargs)
models
from django.contrib import admin
from django.urls import path
from app import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.login),
    path('bind/', views.bind),
    path('bind_qrcode/', views.bindQrcode),
    path('callback/', views.callback),
    path('sendmsg/', views.sendmsg)
]
urls
from django.shortcuts import render, HttpResponse, redirect
from django.http import JsonResponse
from django.conf import settings
import requests
from app import models
import json


# Create your views here.
def login(request):
    """
    用戶登錄
    :param request:
    :return:
    """
    # models.UserInfo.objects.create(username='luffy',password=123)

    if request.method == "POST":
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')
        obj = models.UserInfo.objects.filter(username=user, password=pwd).first()
        if obj:
            request.session['user_info'] = {'id': obj.id, 'name': obj.username, 'uid': obj.uid}
            return redirect('/bind/')
    else:
        return render(request, 'login.html')


def bind(request):
    """用戶綁定頁面"""
    return render(request, 'auth.html')


def bindQrcode(request):
    """生成二維碼"""
    ret = {'code': 1000}
    try:
        access_url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={appid}&redirect_uri={redirect_uri}&response_type=code&scope=snsapi_userinfo&state={state}#wechat_redirect"
        access_url = access_url.format(
            appid=settings.WECHAT_CONFIG["app_id"],
            redirect_uri=settings.WECHAT_CONFIG["redirect_uri"],
            state=request.session['user_info']['uid']
        )
        ret['data'] = access_url
    except Exception as e:
        ret['code'] = 1001
        ret['msg'] = str(e)
    return JsonResponse(ret)


def callback(request):
    """
    用戶在手機微信上掃碼後,微信自動調用該方法。
    用於獲取掃碼用戶的唯一ID,以後用於給他推送消息。
    :param request:
    :return:
    """
    code = request.GET.get("code")

    # 用戶UID
    state = request.GET.get("state")

    # 獲取該用戶openId(用戶唯一,用於給用戶發送消息)
    res = requests.get(
        url="https://api.weixin.qq.com/sns/oauth2/access_token",
        params={
            "appid": settings.WECHAT_CONFIG["app_id"],
            "secret": settings.WECHAT_CONFIG["appsecret"],
            "code": code,
            "grant_type": 'authorization_code',
        }
    ).json()
    # 獲取的到openid表示用戶授權成功

    openid = res.get("openid")
    if openid:
        models.UserInfo.objects.filter(uid=state).update(wx_id=openid)
        response = "<h1>授權成功 %s </h1>" % openid
    else:
        response = "<h1>用戶掃碼之後,手機上的提示</h1>"
    return HttpResponse(response)


def get_access_token():
    """獲取token"""
    result = requests.get(
        url='https://api.weixin.qq.com/cgi-bin/token',
        params={
            "grant_type": "client_credential",
            "appid": settings.WECHAT_CONFIG['app_id'],
            "secret": settings.WECHAT_CONFIG['appsecret'],
        }
    ).json()
    if result.get('access_token'):
        access_token = result.get('access_token')
    else:
        access_token = None
    return access_token


def send_content_msg(user_id, access_token):
    """內容消息發送"""
    body = {
        'touser': user_id,
        'msgtype': 'text',
        'text': {
            'content': '內容。。。。。不是模板消息'
        }
    }
    response = requests.post(
        url='https://api.weixin.qq.com/cgi-bin/message/custom/send',
        params={
            'access_token': access_token
        },
        data=bytes(json.dumps(body, ensure_ascii=False), encoding='utf-8')
    )
    result = response.json()
    return result


def send_template_msg(user_id, access_token):
    """模板消息發送"""
    result = requests.post(
        url='https://api.weixin.qq.com/cgi-bin/message/template/send',
        params={
            'access_token': access_token
        },
        json={
            "touser": user_id,
            "template_id": settings.WECHAT_CONFIG['template_id'],
            "data": {
                "first": {
                    "value": "微信模板頁面發送消息",
                    "color": "#173177"
                },
                "kw1": {
                    "value": "卧槽調這個參數搞了有點久",
                    "color":"#173177"
                },
                "kw2": {
                    "value": "可不是咋地"
                },
                "kw3": {
                    "value": "就看這次能不能成功了"
                },
            }
        }
    )
    result = result.json()
    return result


def sendmsg(requet):
    access_token = get_access_token()
    # 這裡由於我本來就只有一個數據,所以直接寫死了,真實的開發當然是用當前登錄用戶掃碼關註的用戶對應
    userobj = models.UserInfo.objects.filter(id=1).first()
    # 發送模板消息
    result = send_template_msg(userobj.wx_id, access_token)

    # 發送正文消息
    # result = send_content_msg(userobj.wx_id, access_token)

    if result.get('errcode') == 0:
        return HttpResponse('發送成功')
    return HttpResponse('發送失敗')
views
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用戶授權</title>
    <script src="{% static "js/jquery.min.js" %}"></script>
    <script src="{% static "js/jquery.qrcode.min.js" %}"></script>
    <script src="{% static "js/qrcode.js" %}"></script>
</head>
<body>
<input onclick="userauth() " type="button" value="關註我們有驚喜哦">
<div>
    <img style="height: 100px;width: 100px" src="{% static 'img/wx.jpg' %}">
</div>
<div id="qrcode" style="width: 250px;height: 250px;background-color: white;margin: 100px auto;"></div>
<script type="text/javascript">
    function userauth() {
        $.ajax({
            url: '/bind_qrcode/',
            type: 'GET',
            success: function (data) {
                console.log(data);
                $('#qrcode').empty().qrcode({text: data.data});
            }
        });
    }
</script>
</body>
</html>
html:auth.html
ALLOWED_HOSTS = ['192.168.0.8']


STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

# ############# 微信 ##############
WECHAT_CONFIG = {
    'app_id': '您的微信app測試id',  # 微信給的測試app id
    'appsecret': '您的微信app測試secret',  # 微信給的測試app sercret
    'redirect_uri': 'http://您的功能變數名稱地址/callback/',  # 用戶關註之後微信回傳地址
    'template_id': "您的微信測試模板id"  # 模板id
}
settings主要的改動部分
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/login/" method="post">
        {% csrf_token %}
        <input type="text" name="user" placeholder="用戶名">
        <input type="password" name="pwd" placeholder="密碼">
        <input type="submit" value="登錄">
    </form>
</body>
</html>
html:login.html

 

 

總結:

感覺還是挺簡單的,就是對於剛接觸的朋友來說的話,可能不習慣去看第三方的API文檔,也不知道怎麼下手,多研究就行了,熟練了就很快了

微信支付那個,我沒有企業相關材料,而且就算有,也不敢那麼隨意的就為了做個測試就去申請什麼的,所以相關的還是看官方文檔吧

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 推薦8款最好用的前端開發工具供美工或者前端開發人員使用,當然若你是NB的全棧工程師也可以下載使用。 ...
  • 1.代碼 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> 5 <title>OpenLayers</title> 6 <link re ...
  • 我們都都知道kafka的消費組要rebalance,需要觸發以下3個條件之一: 組成員變更,比如新consumer加入組,或已有consumer主動離開組,再或是已有consumer崩潰時則出發rebalance. 組訂閱topic數發生變更,比如使用基於正則表達式的訂閱,當匹配正則表達式的新top ...
  • 一、如何安裝Angular 在文件夾中打開cmd,輸入nmp init創建一個package.json。這個可以一路回車跳過(如果沒有特別要註明)。nmp是前臺的包,用於管理後臺。成功創建package.json後再輸入nmp install bower -g,bower推薦安裝到全局,這裡bowe ...
  • 近來經常用到分散式事務,這裡總結一下,我們目前的使用場景基本都是採用事務消息方式。那麼說到分散式不得不談的CAP CAP理論概述 一個分散式系統最多只能同時滿足一致性(Consistency)、可用性(Availability)和分區容錯性(Partition tolerance)這三項中的兩項。 ...
  • 前言 以前總是採用很Low的方式太同一臺伺服器上部署多個Web應用,步驟是這樣的:Copy Tomcat目錄-->更改conf/server.xml三個埠號 >部署war包 >分別啟動訪問。 這樣是最簡單的方式,但事實上是不推薦的,因為如果伺服器資源有限,需要部署的應用數目一旦增加,會給伺服器帶來 ...
  • Spring Cloud是什麼? Spring Cloud是一系列框架的有序集合。它利用Spring Boot的開發便利性巧妙地簡化了分散式系統基礎設施的開發,如服務發現註冊、配置中心、消息匯流排、負載均衡、斷路器、數據監控等,都可以用Spring Boot的開發風格做到一鍵啟動和部署。Spring並 ...
  • 題意 "鏈接" 長度為$n$的序列,用紅黃藍綠染色,其中紅黃只能是偶數,問方案數 Sol 生成函數入門題 任意的是$e^x$,偶數的是$\frac{e^x + e^{ x}}{2}$ 最後化完是$\frac{e^{4x} + 2e^{2x}+1}{4} = \frac{4^n+2 2^{n+1}}{ ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...