запрос на публикацию работает в браузере, выдает 400 в терминале

#python #flask #python-requests

Вопрос:

Я создаю приложение flask и пытаюсь отправлять запросы post в терминале с помощью requests библиотеки, но оно выдает ошибку 400, но я не знаю, что неправильно в запросе.

Вот страница регистрации, которую я пытаюсь найти в своем браузере:

введите описание изображения здесь

И последующий результат после отправки поста:

введите описание изображения здесь

Однако, когда я пытаюсь воссоздать этот запрос post и использовать ту же информацию в командной строке, я получаю 400 код состояния.

Вот базовый код, который я использую для его создания:

форма:

 class SignupForm(FlaskForm):
    """Main form for sign up page"""
    email          = EmailField(label       = 'email', validators = [DataRequired(), Email()])
    password       = PasswordField(label    = 'password', 
                                 validators = [DataRequired(), Length(min=9, max=20), 
                                                check_valid_password])
    sec_question   = SelectField(label      = 'Security Question', 
                             validators     = [DataRequired()],
                             choices        = ['What is your favorite band?',
                                               'What is your favorite pets name?',
                                               'What was the last name of your favorite childhoold teacher?',
                                               'In what city were you born?',
                                               'What is your best friends last name?', 
                                               'What is the country you would most like to visit?'])
    sec_answer     = TextField(label='your answer.  not case sensitive', validators=[DataRequired(), Length(4, 200)])
 

Вот код колбы, который обрабатывает входящий запрос:

 @user.route('/signup', methods=['GET', 'POST'])
def signup():
form = SignupForm()

if form.validate_on_submit():
    user_exists = User.query.filter_by(email = request.form.get('email')).first()
    if user_exists:
        flash('User already exists with that e-mail.  Please login instead', 'warning')
        return redirect(url_for('user.signup', form = form))

    user          = User()
    form.populate_obj(user)
    user.password =  User.encrypt_password(request.form.get('password'))
    user.save()

    # send confirmation e-mail using celery
    from app.blueprints.main.tasks import send_email

    token = generate_new_account_token(form.email.data)

    send_email.delay(
        subject     = 'Welcome to CPM!  Please confirm your account',
        recipients  = [form.email.data],
        template    = 'email/user_new_confirm.html',
        confirm_url = url_for('user.confirm_new', token = token, _external=True)
    )

    flash(f'A confirmation e-mail has been sent to {form.email.data}', 'info')
    redirect(url_for('user.signup', form=form))

return render_template('blueprints/user/signup.html', form=form)
 

Я ни за что на свете не могу заставить это работать внутри почтового запроса. Он работает localhost:5000 на моем компьютере.

Вот два примера, иллюстрирующих эту проблему. Моя успешная GET просьба:

введите описание изображения здесь

Моя неудачная POST просьба:

 data = {'email': 'myemail@gmail.com', 'password': 'Passw0rd!', 'sec_question': 'What is your favorite band?', 'sec_answer': 'paul simon'}
requests.post('http://localhost:5000/signup', data = data)
 

введите описание изображения здесь

Комментарии:

1. Похоже, что используемый вами запрос sec_question не соответствует ни одному из вариантов. «Какая ваша любимая группа? «против» Какой ваш любимый музыкальный исполнитель?»

2. @Nickodell только что внес изменения, но результаты те же.

Ответ №1:

В качестве меры безопасности формы должны отправлять маркер CSRF вместе с запросом POST для предотвращения атак CSRF (Подделка межсайтовых запросов, иногда сокращенно XSRF). Браузеры справятся с этим за вас, но в cURL вам придется вручную извлекать и использовать токен CSRF (что обычно вызывает боль в шее).

В целях разработки вы можете временно отключить защиту CSRF. Вот объяснение того, как это сделать с помощью колбы.

По сути, просто добавьте @csrf.exempt декоратора в свой signup метод:

 from flask_wtf import csrf

@user.route('/signup', methods=['GET', 'POST'])
@csrf.exempt
def signup():
     # The rest of the method
 

Кроме того, вы можете быстро и легко отключить CSRF для всех ваших представлений, установив значение WTF_CSRF_CHECK_DEFAULT False .

ПРЕДУПРЕЖДЕНИЕ: Никогда не перемещайте представление формы в рабочую среду с отключенной защитой CSRF.