Django開發(fā)時如何避免頻繁發(fā)送短信驗證碼(python圖文代碼)
避免頻繁發(fā)送 驗證碼
存在的問題:
- 雖然我們在前端界面做了60秒倒計時功能。
- 但是惡意用戶可以繞過前端界面向后端頻繁請求 驗證碼。
解決辦法:
- 在后端也要限制用戶請求 驗證碼的頻率。60秒內(nèi)只允許一次請求 驗證碼。
- 在Redis數(shù)據(jù)庫中緩存一個數(shù)值,有效期設置為60秒。
1. 避免頻繁發(fā)送 驗證碼邏輯分析

2. 避免頻繁發(fā)送 驗證碼邏輯實現(xiàn)
1.提取、校驗send_flag
send_flag = redis_conn.get('send_flag_%s' % mobile)
if send_flag:
return http.JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '發(fā)送 過于頻繁'})
2.重新寫入send_flag
# 保存 驗證碼
redis_conn.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
# 重新寫入send_flag
redis_conn.setex('send_flag_%s' % mobile, constants.SEND_SMS_CODE_INTERVAL, 1)3.界面渲染頻繁發(fā)送 提示信息
if (response.data.code == '4001') {
this.error_image_code_message = response.data.errmsg;
this.error_image_code = true;
} else { // 4002
this.error_sms_code_message = response.data.errmsg;
this.error_sms_code = true;
}
pipeline操作Redis數(shù)據(jù)庫
Redis的 C - S 架構(gòu):
- 基于客戶端-服務端模型以及請求/響應協(xié)議的TCP服務。
- 客戶端向服務端發(fā)送一個查詢請求,并監(jiān)聽Socket返回。
- 通常是以阻塞模式,等待服務端響應。
- 服務端處理命令,并將結(jié)果返回給客戶端。
存在的問題:
- 如果Redis服務端需要同時處理多個請求,加上網(wǎng)絡延遲,那么服務端利用率不高,效率降低。
解決的辦法:
- 管道pipeline

1. pipeline的介紹
管道pipeline
- 可以一次性發(fā)送多條命令并在執(zhí)行完后一次性將結(jié)果返回。
- pipeline通過減少客戶端與Redis的通信次數(shù)來實現(xiàn)降低往返延時時間。
實現(xiàn)的原理
- 實現(xiàn)的原理是隊列。
- Client可以將三個命令放到一個tcp報文一起發(fā)送。
- Server則可以將三條命令的處理結(jié)果放到一個tcp報文返回。
- 隊列是先進先出,這樣就保證數(shù)據(jù)的順序性。

2. pipeline操作Redis數(shù)據(jù)庫
1.實現(xiàn)步驟
1. 創(chuàng)建Redis管道 2. 將Redis請求添加到隊列 3. 執(zhí)行請求
2.代碼實現(xiàn)
# 創(chuàng)建Redis管道
pl = redis_conn.pipeline()
# 將Redis請求添加到隊列
pl.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
pl.setex('send_flag_%s' % mobile, constants.SEND_SMS_CODE_INTERVAL, 1)
# 執(zhí)行請求
pl.execute()
生產(chǎn)者消費者設計模式
思考:
- 下面兩行代碼存在什么問題?

問題:
- 我們的代碼是自上而下同步執(zhí)行的。
- 發(fā)送 是耗時的操作。如果 被阻塞住,用戶響應將會延遲。
- 響應延遲會造成用戶界面的倒計時延遲。

解決:
- 異步發(fā)送
- 發(fā)送 和響應分開執(zhí)行,將**
發(fā)送從主業(yè)務中解耦**出來。

思考:
- 如何將**
發(fā)送從主業(yè)務中解耦**出來。
生產(chǎn)者消費者設計模式介紹
- 為了將**
發(fā)送從主業(yè)務中解耦出來,我們引入生產(chǎn)者消費者設計模式**。 - 它是最常用的解耦方式之一,尋找**中間人(broker)**搭橋,保證兩個業(yè)務沒有直接關聯(lián)。

總結(jié):
- 生產(chǎn)者生成消息,緩存到消息隊列中,消費者讀取消息隊列中的消息并執(zhí)行。
- 由美多商城生成發(fā)送 消息,緩存到消息隊列中,消費者讀取消息隊列中的發(fā)送 消息并執(zhí)行。
RabbitMQ介紹和使用
1. RabbitMQ介紹
消息隊列是消息在傳輸?shù)倪^程中保存消息的容器。
現(xiàn)在主流消息隊列有:
RabbitMQ、ActiveMQ、Kafka等等。RabbitMQ和ActiveMQ比較
- 系統(tǒng)吞吐量:
RabbitMQ好于ActiveMQ - 持久化消息:
RabbitMQ和ActiveMQ都支持 - 高并發(fā)和可靠性:
RabbitMQ好于ActiveMQ
- 系統(tǒng)吞吐量:
RabbitMQ和Kafka:
- 系統(tǒng)吞吐量:
RabbitMQ弱于Kafka - 可靠性和穩(wěn)定性:
RabbitMQ好于Kafka比較 - 設計初衷:
Kafka是處理日志的,是日志系統(tǒng),所以并沒有具備一個成熟MQ應該具備的特性。
- 系統(tǒng)吞吐量:
綜合考慮,本項目選擇RabbitMQ作為消息隊列。
2. 安裝RabbitMQ(ubuntu 16.04)
1.安裝Erlang
- 由于 RabbitMQ 是采用 Erlang 編寫的,所以需要安裝 Erlang 語言庫。
# 1. 在系統(tǒng)中加入 erlang apt 倉庫 $ wget $ sudo dpkg -i erlang-solutions_1.0_all.deb # 2. 修改 Erlang 鏡像地址,默認的下載速度特別慢 $ vim /etc/apt/sources.list.d/erlang-solutions.list # 替換默認值 $ deb xenial contrib # 3. 更新 apt 倉庫和安裝 Erlang $ sudo apt-get update $ sudo apt-get install erlang erlang-nox
2.安裝RabbitMQ
- 安裝成功后,默認就是啟動狀態(tài)。
# 1. 先在系統(tǒng)中加入 rabbitmq apt 倉庫,再加入 rabbitmq signing key $ echo 'deb testing main' | sudo tee /etc/apt/sources.list.d/rabbitmq.list $ wget -O- | sudo apt-key add - # 2. 更新 apt 倉庫和安裝 RabbitMQ $ sudo apt-get update $ sudo apt-get install rabbitmq-server
# 重啟 $ sudo systemctl restart rabbitmq-server # 啟動 $ sudo systemctl start rabbitmq-server # 關閉 $ sudo systemctl stop rabbitmq-server
3.Python訪問RabbitMQ
- RabbitMQ提供默認的administrator賬戶。
- 用戶名和密碼:
guest、guest - 協(xié)議:
amqp - 地址:
localhost - 端口:
5672 - 查看隊列中的消息:
sudo rabbitctl list_queues
# Python3虛擬環(huán)境下,安裝pika $ pip install pika
# 生產(chǎn)者代碼:rabbitmq_producer.py
import pika
# 鏈接到RabbitMQ服務器
credentials = pika.PlainCredentials('guest', 'guest')
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672,'/',credentials))
#創(chuàng)建頻道
channel = connection.channel()
# 聲明消息隊列
channel.queue_declare(queue='zxc')
# routing_key是隊列名 body是要插入的內(nèi)容
channel.basic_publish(exchange='', routing_key='zxc', body='Hello RabbitMQ!')
print("開始向 'zxc' 隊列中發(fā)布消息 'Hello RabbitMQ!'")
# 關閉鏈接
connection.close()
# 消費者代碼:rabbitmq_customer.py
import pika
# 鏈接到rabbitmq服務器
credentials = pika.PlainCredentials('guest', 'guest')
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672,'/',credentials))
# 創(chuàng)建頻道,聲明消息隊列
channel = connection.channel()
channel.queue_declare(queue='zxc')
# 定義接受消息的回調(diào)函數(shù)
def callback(ch, method, properties, body):
print(body)
# 告訴RabbitMQ使用callback來接收信息
channel.basic_consume(callback, queue='zxc', no_ack=True)
# 開始接收信息
channel.start_consuming()
3. 新建administrator用戶
# 新建用戶,并設置密碼 $ sudo rabbitmqctl add_user admin your_password # 設置標簽為administrator $ sudo rabbitmqctl set_user_tags admin administrator # 設置所有權(quán)限 $ sudo rabbitmqctl set_permissions -p / admin ".*" ".*" ".*" # 查看用戶列表 sudo rabbitmqctl list_users # 刪除用戶 $ sudo rabbitmqctl delete_user admin

4. RabbitMQ配置遠程訪問
1.準備配置文件
- 安裝好
RabbitMQ之后,在/etc/rabbitmq目錄下面默認沒有配置文件,需要單獨下載。
$ cd /etc/rabbitmq/ $ wget $ sudo cp rabbitmq.config.example rabbitmq.config

2.設置配置文件
$ sudo vim rabbitmq.config # 設置配置文件結(jié)束后,重啟RabbitMQ服務端 $ sudo systemctl restart rabbitmq-server

配置完成后,使用rabbitmq_producer.py、rabbitmq_customer.py測試。
Celery介紹和使用
思考:
- 消費者取到消息之后,要消費掉(執(zhí)行任務),需要我們?nèi)崿F(xiàn)。
- 任務可能出現(xiàn)高并發(fā)的情況,需要補充多任務的方式執(zhí)行。
- 耗時任務很多種,每種耗時任務編寫的生產(chǎn)者和消費者代碼有重復。
- 取到的消息什么時候執(zhí)行,以什么樣的方式執(zhí)行。
結(jié)論:
- 實際開發(fā)中,我們可以借助成熟的工具
Celery來完成。 - 有了
Celery,我們在使用生產(chǎn)者消費者模式時,只需要關注任務本身,極大的簡化了程序員的開發(fā)流程。
1. Celery介紹
Celery介紹:
- 一個簡單、靈活且可靠、處理大量消息的分布式系統(tǒng),可以在一臺或者多臺機器上運行。
- 單個 Celery 進程每分鐘可處理數(shù)以百萬計的任務。
- 通過消息進行通信,使用
消息隊列(broker)在客戶端和消費者之間進行協(xié)調(diào)。
安裝Celery:
$ pip install -U Celery
- [Celery官方文檔]
2. 創(chuàng)建Celery實例并加載配置
1.定義Celery包

2.創(chuàng)建Celery實例

celery_tasks.main.py
# celery啟動文件
from celery import Celery
# 創(chuàng)建celery實例
celery_app = Celery('meiduo')3.加載Celery配置

celery_tasks.config.py
# 指定消息隊列的位置 broker_url= 'amqp://guest:guest@192.168.103.158:5672'
celery_tasks.main.py
# celery啟動文件
from celery import Celery
# 創(chuàng)建celery實例
celery_app = Celery('meiduo')
# 加載celery配置
celery_app.config_from_object('celery_tasks.config')3. 定義發(fā)送 任務

1.注冊任務:celery_tasks.main.py
# celery啟動文件
from celery import Celery
# 創(chuàng)建celery實例
celery_app = Celery('meiduo')
# 加載celery配置
celery_app.config_from_object('celery_tasks.config')
# 自動注冊celery任務
celery_app.autodiscover_tasks(['celery_tasks.sms'])2.定義任務:celery_tasks.sms.tasks.py
# bind:保證task對象會作為第一個參數(shù)自動傳入
# name:異步任務別名
# retry_backoff:異常自動重試的時間間隔 第n次(retry_backoff×2^(n-1))s
# max_retries:異常自動重試次數(shù)的上限
@celery_app.task(bind=True, name='ccp_send_sms_code', retry_backoff=3)
def ccp_send_sms_code(self, mobile, sms_code):
"""
發(fā)送 異步任務
:param mobile: 手機號
:param sms_code: 驗證碼
:return: 成功0 或 失敗-1
"""
try:
send_ret = CCP().send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES // 60], constants.SEND_SMS_TEMPLATE_ID)
except Exception as e:
logger.error(e)
# 有異常自動重試三次
raise self.retry(exc=e, max_retries=3)
if send_ret != 0:
# 有異常自動重試三次
raise self.retry(exc=Exception('發(fā)送 失敗'), max_retries=3)
return send_ret4. 啟動Celery服務
$ cd ~/projects/meiduo_project/meiduo_mall $ celery -A celery_tasks.main worker -l info
-A指對應的應用程序, 其參數(shù)是項目中 Celery實例的位置。worker指這里要啟動的worker。-l指日志等級,比如info等級。

5. 調(diào)用發(fā)送 任務
# 發(fā)送 驗證碼 # CCP().send_template_sms(mobile,[sms_code, constants.SMS_CODE_REDIS_EXPIRES // 60], constants.SEND_SMS_TEMPLATE_ID) # Celery異步發(fā)送 驗證碼 ccp_send_sms_code.delay(mobile, sms_code)

6. 補充celery worker的工作模式
- 默認是進程池方式,進程數(shù)以當前機器的CPU核數(shù)為參考,每個CPU開四個進程。
- 如何自己指定進程數(shù):
celery worker -A proj --concurrency=4 - 如何改變進程池方式為協(xié)程方式:
celery worker -A proj --concurrency=1000 -P eventlet -c 1000
# 安裝eventlet模塊 $ pip install eventlet # 啟用 Eventlet 池 $ celery -A celery_tasks.main worker -l info -P eventlet -c 1000

總結(jié)
到此這篇關于Django開發(fā)時如何避免頻繁發(fā)送短信驗證碼(python圖文代碼)的文章就介紹到這了,更多相關Django避免頻繁發(fā)送短信驗證碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
三步解決python PermissionError: [WinError 5]拒絕訪問的情況
這篇文章主要介紹了三步解決python PermissionError: [WinError 5]拒絕訪問的情況,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04
使用pytorch提取卷積神經(jīng)網(wǎng)絡的特征圖可視化
這篇文章主要給大家介紹了關于使用pytorch提取卷積神經(jīng)網(wǎng)絡的特征圖可視化的相關資料,文中給出了詳細的思路以及示例代碼,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2022-03-03
LyScript實現(xiàn)計算片段Hash并寫出Excel的示例代碼
本案例將學習運用LyScript計算特定程序中特定某些片段的Hash特征值,并通過xlsxwriter這個第三方模塊將計算到的hash值存儲成一個excel表格,感興趣的可以跟隨小編一起學習一下2022-09-09

