Django開發(fā)時如何避免頻繁發(fā)送短信驗證碼(python圖文代碼)
避免頻繁發(fā)送 驗證碼
存在的問題:
- 雖然我們在前端界面做了60秒倒計時功能。
- 但是惡意用戶可以繞過前端界面向后端頻繁請求 驗證碼。
解決辦法:
- 在后端也要限制用戶請求 驗證碼的頻率。60秒內(nèi)只允許一次請求 驗證碼。
- 在Redis數(shù)據(jù)庫中緩存一個數(shù)值,有效期設(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):
- 基于客戶端-服務(wù)端模型以及請求/響應(yīng)協(xié)議的TCP服務(wù)。
- 客戶端向服務(wù)端發(fā)送一個查詢請求,并監(jiān)聽Socket返回。
- 通常是以阻塞模式,等待服務(wù)端響應(yīng)。
- 服務(wù)端處理命令,并將結(jié)果返回給客戶端。
存在的問題:
- 如果Redis服務(wù)端需要同時處理多個請求,加上網(wǎng)絡(luò)延遲,那么服務(wù)端利用率不高,效率降低。
解決的辦法:
- 管道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)者消費者設(shè)計模式
思考:
- 下面兩行代碼存在什么問題?
問題:
- 我們的代碼是自上而下同步執(zhí)行的。
- 發(fā)送 是耗時的操作。如果 被阻塞住,用戶響應(yīng)將會延遲。
- 響應(yīng)延遲會造成用戶界面的倒計時延遲。
解決:
- 異步發(fā)送
- 發(fā)送 和響應(yīng)分開執(zhí)行,將**
發(fā)送
從主業(yè)務(wù)中解耦
**出來。
思考:
- 如何將**
發(fā)送
從主業(yè)務(wù)中解耦
**出來。
生產(chǎn)者消費者設(shè)計模式介紹
- 為了將**
發(fā)送
從主業(yè)務(wù)中解耦
出來,我們引入生產(chǎn)者消費者設(shè)計模式
**。 - 它是最常用的解耦方式之一,尋找**中間人(broker)**搭橋,保證兩個業(yè)務(wù)沒有直接關(guān)聯(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
比較 - 設(shè)計初衷:
Kafka
是處理日志的,是日志系統(tǒng),所以并沒有具備一個成熟MQ應(yīng)該具備的特性。
- 系統(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 # 關(guān)閉 $ 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服務(wù)器 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!'") # 關(guān)閉鏈接 connection.close()
# 消費者代碼:rabbitmq_customer.py import pika # 鏈接到rabbitmq服務(wù)器 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用戶
# 新建用戶,并設(shè)置密碼 $ sudo rabbitmqctl add_user admin your_password # 設(shè)置標簽為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配置遠程訪問
1.準備配置文件
- 安裝好
RabbitMQ
之后,在/etc/rabbitmq
目錄下面默認沒有配置文件,需要單獨下載。
$ 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介紹和使用
思考:
- 消費者取到消息之后,要消費掉(執(zhí)行任務(wù)),需要我們?nèi)崿F(xiàn)。
- 任務(wù)可能出現(xiàn)高并發(fā)的情況,需要補充多任務(wù)的方式執(zhí)行。
- 耗時任務(wù)很多種,每種耗時任務(wù)編寫的生產(chǎn)者和消費者代碼有重復(fù)。
- 取到的消息什么時候執(zhí)行,以什么樣的方式執(zhí)行。
結(jié)論:
- 實際開發(fā)中,我們可以借助成熟的工具
Celery
來完成。 - 有了
Celery
,我們在使用生產(chǎn)者消費者模式時,只需要關(guān)注任務(wù)本身,極大的簡化了程序員的開發(fā)流程。
1. Celery介紹
Celery介紹:
- 一個簡單、靈活且可靠、處理大量消息的分布式系統(tǒng),可以在一臺或者多臺機器上運行。
- 單個 Celery 進程每分鐘可處理數(shù)以百萬計的任務(wù)。
- 通過消息進行通信,使用
消息隊列(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ā)送 任務(wù)
1.注冊任務(wù):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任務(wù) celery_app.autodiscover_tasks(['celery_tasks.sms'])
2.定義任務(wù):celery_tasks.sms.tasks.py
# bind:保證task對象會作為第一個參數(shù)自動傳入 # name:異步任務(wù)別名 # 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ā)送 異步任務(wù) :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_ret
4. 啟動Celery服務(wù)
$ cd ~/projects/meiduo_project/meiduo_mall $ celery -A celery_tasks.main worker -l info
-A
指對應(yīng)的應(yīng)用程序, 其參數(shù)是項目中 Celery實例的位置。worker
指這里要啟動的worker。-l
指日志等級,比如info
等級。
5. 調(diào)用發(fā)送 任務(wù)
# 發(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é)
到此這篇關(guān)于Django開發(fā)時如何避免頻繁發(fā)送短信驗證碼(python圖文代碼)的文章就介紹到這了,更多相關(guān)Django避免頻繁發(fā)送短信驗證碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
三步解決python PermissionError: [WinError 5]拒絕訪問的情況
這篇文章主要介紹了三步解決python PermissionError: [WinError 5]拒絕訪問的情況,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04使用pytorch提取卷積神經(jīng)網(wǎng)絡(luò)的特征圖可視化
這篇文章主要給大家介紹了關(guān)于使用pytorch提取卷積神經(jīng)網(wǎng)絡(luò)的特征圖可視化的相關(guān)資料,文中給出了詳細的思路以及示例代碼,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2022-03-03LyScript實現(xiàn)計算片段Hash并寫出Excel的示例代碼
本案例將學(xué)習(xí)運用LyScript計算特定程序中特定某些片段的Hash特征值,并通過xlsxwriter這個第三方模塊將計算到的hash值存儲成一個excel表格,感興趣的可以跟隨小編一起學(xué)習(xí)一下2022-09-09