萌新在写网站的发送邮件验证,为了防止用户滥发,所以加了权限。前端简单地disable按钮一刷新就没了,纯粹视觉提示作用,所以在后端models里为user加了一个resend_right,当为True时才能重新发送,False不行。
所以在models里,user模型有一个column是这样的(SQLAlchemy):
resend_right = db.Column(db.Boolean, default=True)
当然前端是等待60秒后可以重新发送,所以后端也计时60秒后重新赋值True给resend_right。我就想这种等待性IO/数据库读取录入等操作当然是多线程处理。
所以我写了resend_right权限重置的方法:
def async_reset(app, user):
with app.app_context():
time.sleep(55)
user.resend_right = True
def resend_right_reset(user):
app = current_app._get_current_object()
thr = Thread(target=async_reset, args=[app, user])
thr.start()
return thr
然后在views的路由函数里面调用它:
# Resend confirmation email route, need to be protected
@auth.route('/resend_email/')
@login_required
def resend_confirmation():
mail_host ='http://mail.' + re.split('@', current_user.email)[1]
if not current_user.resend_right:
flash("请不要尝试刷新页面来短时间内重复发送验证邮件,你可以在一分钟后再试")
return render_template('auth/confirm.html',user=current_user, mail_host=mail_host)
token = current_user.generate_confirmation_token()
.........
结果无效,所以我测试了一下,发现路由函数无问题,resend_right_reset无问题。假如我把user.rend_right=True写进resend_right_reset是能够正常运作的,但一旦用多线程来处理就始终无法重置。然后我分析,多线程这里用了current_app._get_current_object()获取全局对象,然后app.app_context()拿到了上下文导入到多线程里,应该就没问题了。但为什么不行?
求教,非常感谢!
Beritahu saya idea yang tiada kaitan dengan topik ini.
Untuk kod pengesahan, anda boleh menggunakan redis untuk menyimpannya dan menetapkan masa kelangsungan hidup Sebaik sahaja masa tamat, nilai yang sepadan akan hilang dalam redis. Hanya pergi ke redis untuk mendapatkan nilai yang diserahkan Caching pangkalan data akan menjadi lebih pantas daripada sql, dan boleh menghalang orang lain daripada mengubah suai parameter dan menyerahkannya. Secara peribadi, saya rasa tidak sesuai untuk menambah cap masa kerana saya boleh mengubah suai parameter yang diserahkan secara langsung.
Saya ada dua tekaan:
Dalam mekanisme pelaksanaan
flask
, beberapa objek global termasukcurrent_app
adalah semua objek proksi Proksi ialah elemen teratas tindanan yang sepadan dengan tindanan tempatan ialah pembolehubah setempat benang (Threading Local), yang bermaksud bahawa untuk setiap permintaan, rujukan kepada objek dengan nama yang sama adalah berbeza.Saya tidak melihat kod komit dalam async_reset, jadi saya rasa
current_user
dalam kod penghalaan di belakang harus diperoleh semula daripada pangkalan data, bukan objek yang pada asalnya dikemas kini oleh anda (rujukan adalah berbeza). Jadi cuba lakukan?Sebenarnya, penyelesaian ini tidak begitu baik, sebaiknya tulis masa penghantaran semasa menghantar e-mel, dan kemudian tentukan selang dari masa semasa hingga masa penghantaran terakhir dalam penghalaan. Ini mengelakkan overhed penulisan pangkalan data dan memperuntukkan benang.
Setelah diingatkan oleh @TKfeng, redis cache + TTL adalah penyelesaian yang sesuai. Ia mempunyai prestasi yang baik dan sesuai untuk pembahagian perkhidmatan yang halus di peringkat seterusnya.