1. 程式人生 > >python:python bottle實現jquery ajax調取資料藉口

python:python bottle實現jquery ajax調取資料藉口

開發環境:

  • python 3.6+
  • python bottle 0.13

需求

後臺路由框架與ajax的配合不友好,大概是通病,雖然bottle 已經提供了非常強大的請求處理方法,但是都基於頁面重載入,在某些場景,其實並不需要重載入頁面,只是需要向後端傳送請求,得到請求已經接收的響應即可。如下圖所示場景: 這裡寫圖片描述

在註冊過程中,通過所輸入郵箱,點選獲取驗證碼,只需向後端傳送請求,讓後端傳送郵件到輸入郵箱,根本不需要重新整理當前頁面。要實現無重新整理,jquery ajax是一個比較好的方法之一。

實現原理

註冊頁面html程式碼

<form action="/sign_do"
method="post">
<div class="form-group login_header"> <div class="row"> <div class="col-sm-4"> <span><strong>註冊</strong></span> </div> <div class="col-sm-8 go_sign"> <a
href="/login">
已有賬號?去登入>></a> </div> </div> </div> <div class="form-group"> <label for="InputEmail1">Email address</label> <input type="email" class="form-control" id="InputEmail1" placeholder="Email" name="username"
value="
{{username}}"> </div> <div class="form-group"> <label for="InputVerification">驗證碼</label> <div class="row"> <div class="col-md-7"> <input type="text" class="form-control" id="InputVerification" placeholder="ver_code" name="ver_code"> </div> <div class="col-md-5"> <button type="button" class="btn btn-default btn_ver_code">獲取驗證碼</button> </div> </div> </div> <div class="form-group"> <label for="InputPassword1">Password</label> <input type="password" class="form-control" id="InputPassword1" placeholder="Password" name="password1"> </div> <div class="form-group"> <label for="InputPassword2">Password</label> <input type="password" class="form-control" id="InputPassword2" placeholder="Password" name="password2"> <p class="help-block warning">{{message}}</p> <p class="help-block error"></p> </div> <button type="submit" class="btn btn_do">確定</button> </form>

傳送ajax請求js程式碼

<script>
    $(".btn_ver_code").bind("click", function(ev){
        var username = $("#InputEmail1").val();
        $(".help-block.warning").hide();
        if($.trim(username) == ''){
            $(".help-block.error").text("郵箱不能為空!");
            return false;
        }
        $(".help-block.error").text("請求已傳送,請耐心等待郵件傳送提示。");
        $.ajax({
            type: 'POST',
            url: '/sign/get_ver_code',
            data: {_method: 'get', _form: username},
            dataType: 'json',
            success: function (data){
                $(".help-block.error").text(data.get_ver_code_state);
            },
            error: function () {

            }
        });
    });
</script>

這樣,獲取的驗證碼的請求就到傳送到後臺了,但是bottle route是無法直接接受ajax請求的,這時候需要在後臺全域性方法裡註冊一個請求,用來捕捉ajax,也就是hook(鉤子),程式碼如下

@hook('before_request')
def validate():
    """使用勾子處理頁面或介面訪問事件"""
    if request.method == 'POST' and request.POST.get('_method'):
        request.environ['REQUEST_METHOD'] = request.POST.get('_method', '').upper()
        if request.POST.get('_form'):
            request.environ['REQUEST_FORM'] = request.POST.get('_form', '')

這段程式碼會攔截所有 ajax 請求,其中 ajax 傳送方式 “POST” 和傳入引數 “_method” 在這裡作為正確請求的標記,當請求正確驗證後,將傳送的資料 “_form” 存入 request.environ[‘REQUEST_FORM’], 其中 REQUEST_FORM 是一個自定義引數。

這一步只是捕捉到了請求,並且捕捉到了請求的所攜帶的資料,還需要一個執行請求的方法,去執行真正 ajax 的 /sign/get_ver_code 方法,程式碼如下:

@get('/sign/get_ver_code')
def sign():
    username = request.environ['REQUEST_FORM']
    sql = """
        SELECT * FROM user WHERE username=%s
    """
    res = Do_sql.readdb(sql, (username, ))
    if not res:
        ver_code = Do_common.create_ver_code()
        apply_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())

        sql = """
            SELECT * FROM user_sign WHERE username=%s
        """
        res = Do_sql.readdb(sql, (username,))
        if len(res) > 0:
            res = res[0]
            apply_s = int(time.mktime(time.strptime(str(res['apply_time']), "%Y-%m-%d %H:%M:%S")))
            active_s = int(time.mktime(time.strptime(apply_time, "%Y-%m-%d %H:%M:%S")))

            if res['apply_res'] == 0 and active_s - apply_s < 3600:
                return {"get_ver_code_state": "操作過於頻繁,上一個驗證碼仍有效。"}

        msg = "註冊驗證碼,請查收".encode('utf-8')
        msg_text = "\n你有兩次嘗試機會,兩次輸錯驗證碼,則驗證碼失效。"
        variable = Do_common.mail_do(username, ver_code, msg, msg_text)
        try:
            smtpObj = smtplib.SMTP()
            smtpObj.connect(variable['mail_host'], 25)  # 25 為 SMTP 埠號
            smtpObj.login(variable['mail_user'], variable['mail_pass'])
            smtpObj.sendmail(variable['mail_user'], variable['receivers'], variable['message'].as_string())

            sql = """
                INSERT INTO user_sign (username, ver_code, apply_time) VALUES (%s, %s, %s)
            """
            res = Do_sql.writedb(sql, (username, ver_code, apply_time))
            if res:
                return {"get_ver_code_state": "驗證碼已傳送,可能被當成垃圾郵件。"}
            else:
                return {"get_ver_code_state": "未知錯誤,郵件傳送錯誤,請重試。"}
        except smtplib.SMTPException:
            return {"get_ver_code_state": "未知錯誤,郵件傳送錯誤,請重試。"}
    else:
        return {"get_ver_code_state": "郵箱已被註冊,請更換郵箱。"}

@get 是 bottle 的方法from bottle import hook, get, put,這裡可以換成 @put。 當該方法開始執行,會根據各種條件,返回最終狀態。前端就可以無重新整理接收,在前端 <p class="help-block error"></p> 這裡顯示