【问题标题】:Flask & AJAX: Failed to load resource: the server responded with a status of 400 (BAD REQUEST)Flask & AJAX:加载资源失败:服务器响应状态为 400(错误请求)
【发布时间】:2017-11-17 13:45:56
【问题描述】:

我正在制作一个用于发送电子邮件的 Flask 应用程序。它工作得很好,直到我决定实现一点 AJAX 以使其更具交互性。

我经常收到 400 错误,我尝试了很多组合,但都注意到了。

有人告诉我问题出在 CSRF 令牌上,但是当我放入 @csrf.exempt 装饰器时,它仍然无法正常工作。请帮忙!

这里是源代码:

1) 烧瓶:

from flask import Flask, render_template, url_for, redirect, request, jsonify
from flask_bootstrap import Bootstrap
from flask_sqlalchemy import SQLAlchemy
from flask_mail import Mail, Message
from flask_wtf.csrf import CSRFProtect
from wtforms import StringField, PasswordField, BooleanField, TextAreaField
from wtforms.validators import InputRequired, Email, Length, AnyOf, Regexp
from flask_wtf import FlaskForm

app = Flask(__name__)
app.config['SECRET_KEY'] = '**********'

mail = Mail(app)
Bootstrap(app)
csrf = CSRFProtect(app)

class LoginForm(FlaskForm):
    email = StringField('Email *', _name='email', validators=[InputRequired(), Email(message='I don\'t like your email.')], render_kw={"placeholder": "Please enter your email"})
    password = PasswordField('Password *', _name='password', validators=[InputRequired(), Length(min=5, max=10), AnyOf(['secret', 'password'])], render_kw={"placeholder": "Please enter your password"})

app.config.update(
    DEBUG = True,
    # EMAIL SETTINGS
    MAIL_SERVER = 'smtp.gmail.com',
    MAIL_PORT = 465,
    MAIL_USE_SSL = True,
    MAIL_USERNAME = 'jakov.kusic92@gmail.com',
    MAIL_PASSWORD = '********'
)

@csrf.exempt
@app.route('/', methods=['GET', 'POST'])
def mailForm():
    form = LoginForm()
    return render_template('loginForm.html', form=form)

@csrf.exempt
@app.route('/process', methods=['POST'])
def process():

    emailInput = request.form['email']
    passwordInput = request.form['password']


    str = 'Hello'
    msg = Message(
        subject=str,
        sender='jakov.kusic92@gmail.com',
        recipients=['jakov.kusic@gmail.com']
    )
    msg.body = """
    NEW USER INFO:
    Email: {}
    Password: {}
    """.format(emailInput, passwordInput)

    if emailInput and passwordInput:
        # mail.send(msg)
        return jsonify({'firstname' : emailInput, 'lastname' : passwordInput})

    return jsonify({'error' : 'Missing data!'})

if __name__ == '__main__':
    app.run(debug=True)

2) HTML:

{% extends "bootstrap/base.html" %}
{% import "bootstrap/wtf.html" as wtf %}

{% block title %}
WTForms
{% endblock %}

{% block head %}
    {{ super() }}
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
    <script src="https://code.jquery.com/jquery-2.2.4.js"></script>
    <script src="{{ url_for('static', filename='form.js') }}" type="text/javascript"></script>

{% endblock %}

{% block content %}
<div class="container">

    <br><br> <!-- br tags are here used for vertical alingment -->
    <div class="col-md-4 col-md-offset-4 col-sm-8 col-sm-offset-2">
        <div class="well">
            <br>
            <h1 class="text-center">Welcome to the database website</h1>
            <br>
            <h2>Please enter your data below:</h2>
            <form>
                <dl>
                    {{ wtf.quick_form(form)}}
                    <input type="submit" value="Login" class="btn btn-info">
                </dl>
            </form>
            <div class="row">
                <div class="col-md-12">
                    <p class="text-muted"><strong>*</strong> These fields are required.</p>
                </div>
            </div>
            <div id="successAlert" class="alert alert-success" role="alert" style="display:none;"></div>
            <div id="errorAlert" class="alert alert-danger" role="alert" style="display:none;"></div>
        </div>
    </div>
</div>
{% endblock %}

3) JS:

$('form').on('submit', function(event) {

    $.ajax({
        data : {
            firstnameInput : $('#firstnameInput').val(),
            lastnameInput : $('#lastnameInput').val(),
            emailInput : $('#emailInput').val(),
            passwordInput : $('#passwordInput').val(),
            messageInput : $('#messageInput').val()
        },
        type : 'POST',
        headers: {
            'Cache-Control': 'no-cache, no-store, must-revalidate',
            'Pragma': 'no-cache',
            'Expires': '0'
        },
        url : '/process',
        dataType: "json",
        contentType: "application/json"
    })
    .done(function(data) {
        $('#successAlert').text(data.firstname + data.lastname).show();
        $('#errorAlert').hide();
    });

    event.preventDefault();

});

这是我在 Chrome 开发工具上获得的:

【问题讨论】:

    标签: jquery ajax flask jinja2


    【解决方案1】:

    您向/process URL 发送带有以下负载的ajax 请求:

        data : {
            firstnameInput : $('#firstnameInput').val(),
            lastnameInput : $('#lastnameInput').val(),
            emailInput : $('#emailInput').val(),
            passwordInput : $('#passwordInput').val(),
            messageInput : $('#messageInput').val()
        }
    

    您尝试在process 路由中处理以下参数:

    emailInput = request.form['email']
    passwordInput = request.form['password']
    

    但是您不会在 ajax 请求负载中发送 emailpassword 键,而是发送 emailInputpasswordInput 参数,所以这就是为什么 Flask 会以 400 状态码响应您 - 没有您尝试在路由功能中使用的 POST 正文中的此类参数。

    你的代码应该是:

    @app.route('/process/', methods=['POST'])
    def process():
    
        emailInput = request.form['emailInput']
        passwordInput = request.form['passwordInput']
    

    就是这样。

    另外建议在网址末尾使用“/”:

    @app.route('/process/', methods=['POST'])
    

    避免 302 重定向到 Flask 所做的/process/ url。

    建议也使用request.form.get('param') 而不是request.form['param'],因为如果dict 中没有指定的键而不是引发异常,.get() 函数将返回 None。

    【讨论】:

      猜你喜欢
      • 2022-06-15
      • 2020-09-21
      • 1970-01-01
      • 2014-10-25
      • 2017-10-20
      • 1970-01-01
      • 1970-01-01
      • 2021-04-12
      • 1970-01-01
      相关资源
      最近更新 更多