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

2. 避免頻繁發(fā)送 驗(yàn)證碼邏輯實(shí)現(xiàn)
1.提取、校驗(yàn)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
# 保存 驗(yàn)證碼
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):
- 基于客戶端-服務(wù)端模型以及請(qǐng)求/響應(yīng)協(xié)議的TCP服務(wù)。
- 客戶端向服務(wù)端發(fā)送一個(gè)查詢請(qǐng)求,并監(jiān)聽Socket返回。
- 通常是以阻塞模式,等待服務(wù)端響應(yīng)。
- 服務(wù)端處理命令,并將結(jié)果返回給客戶端。
存在的問題:
- 如果Redis服務(wù)端需要同時(shí)處理多個(gè)請(qǐng)求,加上網(wǎng)絡(luò)延遲,那么服務(wù)端利用率不高,效率降低。
解決的辦法:
- 管道pipeline

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

2. pipeline操作Redis數(shù)據(jù)庫
1.實(shí)現(xiàn)步驟
1. 創(chuàng)建Redis管道 2. 將Redis請(qǐng)求添加到隊(duì)列 3. 執(zhí)行請(qǐng)求
2.代碼實(shí)現(xiàn)
# 創(chuàng)建Redis管道
pl = redis_conn.pipeline()
# 將Redis請(qǐng)求添加到隊(duì)列
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í)行請(qǐng)求
pl.execute()
生產(chǎn)者消費(fèi)者設(shè)計(jì)模式
思考:
- 下面兩行代碼存在什么問題?

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

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

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

總結(jié):
- 生產(chǎn)者生成消息,緩存到消息隊(duì)列中,消費(fèi)者讀取消息隊(duì)列中的消息并執(zhí)行。
- 由美多商城生成發(fā)送 消息,緩存到消息隊(duì)列中,消費(fèi)者讀取消息隊(duì)列中的發(fā)送 消息并執(zhí)行。
RabbitMQ介紹和使用
1. RabbitMQ介紹
消息隊(duì)列是消息在傳輸?shù)倪^程中保存消息的容器。
現(xiàn)在主流消息隊(duì)列有:
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比較 - 設(shè)計(jì)初衷:
Kafka是處理日志的,是日志系統(tǒng),所以并沒有具備一個(gè)成熟MQ應(yīng)該具備的特性。
- 系統(tǒng)吞吐量:
綜合考慮,本項(xiàng)目選擇RabbitMQ作為消息隊(duì)列。
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 鏡像地址,默認(rèn)的下載速度特別慢 $ vim /etc/apt/sources.list.d/erlang-solutions.list # 替換默認(rèn)值 $ deb xenial contrib # 3. 更新 apt 倉庫和安裝 Erlang $ sudo apt-get update $ sudo apt-get install erlang erlang-nox
2.安裝RabbitMQ
- 安裝成功后,默認(rèn)就是啟動(dòng)狀態(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 # 啟動(dòng) $ sudo systemctl start rabbitmq-server # 關(guān)閉 $ sudo systemctl stop rabbitmq-server
3.Python訪問RabbitMQ
- RabbitMQ提供默認(rèn)的administrator賬戶。
- 用戶名和密碼:
guest、guest - 協(xié)議:
amqp - 地址:
localhost - 端口:
5672 - 查看隊(duì)列中的消息:
sudo rabbitctl list_queues
# Python3虛擬環(huán)境下,安裝pika $ pip install pika
# 生產(chǎn)者代碼:rabbitmq_producer.py
import pika
# 鏈接到RabbitMQ服務(wù)器
credentials = pika.PlainCredentials('guest', 'guest')
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672,'/',credentials))
#創(chuàng)建頻道
channel = connection.channel()
# 聲明消息隊(duì)列
channel.queue_declare(queue='zxc')
# routing_key是隊(duì)列名 body是要插入的內(nèi)容
channel.basic_publish(exchange='', routing_key='zxc', body='Hello RabbitMQ!')
print("開始向 'zxc' 隊(duì)列中發(fā)布消息 'Hello RabbitMQ!'")
# 關(guān)閉鏈接
connection.close()
# 消費(fèi)者代碼:rabbitmq_customer.py
import pika
# 鏈接到rabbitmq服務(wù)器
credentials = pika.PlainCredentials('guest', 'guest')
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672,'/',credentials))
# 創(chuàng)建頻道,聲明消息隊(duì)列
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用戶
# 新建用戶,并設(shè)置密碼 $ sudo rabbitmqctl add_user admin your_password # 設(shè)置標(biāo)簽為administrator $ sudo rabbitmqctl set_user_tags admin administrator # 設(shè)置所有權(quán)限 $ sudo rabbitmqctl set_permissions -p / admin ".*" ".*" ".*" # 查看用戶列表 sudo rabbitmqctl list_users # 刪除用戶 $ sudo rabbitmqctl delete_user admin

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

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

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

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

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

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

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

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

6. 補(bǔ)充celery worker的工作模式
- 默認(rèn)是進(jìn)程池方式,進(jìn)程數(shù)以當(dāng)前機(jī)器的CPU核數(shù)為參考,每個(gè)CPU開四個(gè)進(jìn)程。
- 如何自己指定進(jìn)程數(shù):
celery worker -A proj --concurrency=4 - 如何改變進(jìn)程池方式為協(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é)
到此這篇關(guān)于Django開發(fā)時(shí)如何避免頻繁發(fā)送短信驗(yàn)證碼(python圖文代碼)的文章就介紹到這了,更多相關(guān)Django避免頻繁發(fā)送短信驗(yàn)證碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python 將列表里的字典元素合并為一個(gè)字典實(shí)例
這篇文章主要介紹了python 將列表里的字典元素合并為一個(gè)字典實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09
Python實(shí)現(xiàn)3行代碼解簡單的一元一次方程
這篇文章主要介紹了Python實(shí)現(xiàn)3行代碼解簡單的一元一次方程,很適合Python初學(xué)者學(xué)習(xí)借鑒,需要的朋友可以參考下2014-08-08
Python合并多個(gè)Excel數(shù)據(jù)的方法
這篇文章主要介紹了Python合并多個(gè)Excel數(shù)據(jù)的方法也就是說將多個(gè)excel中的數(shù)據(jù)合并到另一個(gè)表中,本文通過實(shí)例代碼相結(jié)合的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-07-07
三步解決python PermissionError: [WinError 5]拒絕訪問的情況
這篇文章主要介紹了三步解決python PermissionError: [WinError 5]拒絕訪問的情況,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-04-04
Python爬取哆啦A夢(mèng)-伴我同行2豆瓣影評(píng)并生成詞云圖
哆啦A夢(mèng)系列是陪伴我,乃至陪伴了幾代人成長的故事.50年來,藤子·F·不二雄先生創(chuàng)造了竹蜻蜓,任意門,時(shí)光機(jī)器等等無數(shù)的新奇道具,讓大雄和他的小伙伴們經(jīng)歷了各種冒險(xiǎn),也經(jīng)歷了許多充滿戲劇性的啼笑皆非的日常.特意寫了這篇文章,教大家怎么繪制詞云圖,需要的朋友可以參考下2021-06-06
使用pytorch提取卷積神經(jīng)網(wǎng)絡(luò)的特征圖可視化
這篇文章主要給大家介紹了關(guān)于使用pytorch提取卷積神經(jīng)網(wǎng)絡(luò)的特征圖可視化的相關(guān)資料,文中給出了詳細(xì)的思路以及示例代碼,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-03-03
LyScript實(shí)現(xiàn)計(jì)算片段Hash并寫出Excel的示例代碼
本案例將學(xué)習(xí)運(yùn)用LyScript計(jì)算特定程序中特定某些片段的Hash特征值,并通過xlsxwriter這個(gè)第三方模塊將計(jì)算到的hash值存儲(chǔ)成一個(gè)excel表格,感興趣的可以跟隨小編一起學(xué)習(xí)一下2022-09-09

