Python Flask: werkzeug.exceptions.BadRequestKeyError

Oct 08 2020

ฉันเป็นคนใหม่ใน Python Flask และฉันกำลังพยายามออกแบบบล็อกส่วนตัวของฉัน เนื่องจากเป็นเพียงการใช้งานส่วนตัวฉันจึงต้องการเพิ่มหน้า "เพิ่ม" สำหรับโพสต์เป็นพื้นที่คุ้มครองโดยใช้ชื่อผู้ใช้และรหัสผ่านเพื่อเพิ่มและจัดการโพสต์ของฉัน เพื่อไม่ให้แสดงข้อมูลรับรองการเข้าสู่ระบบในซอร์สโค้ดฉันจึงตัดสินใจจัดเก็บในไฟล์. yaml และดึงข้อมูล ( {"Franz":{"pw":"Biberkopf"}}) ผ่านการเข้าสู่ระบบฟังก์ชัน

แต่เมื่อฉันใส่ "Franz" เป็นชื่อผู้ใช้และ "Biberkopf" เป็นรหัสผ่านฉันได้รับข้อผิดพลาดนี้:

werkzeug.exceptions.BadRequestKeyError

werkzeug.exceptions.BadRequestKeyError: 400 คำขอที่ไม่ถูกต้อง: เบราว์เซอร์ (หรือพร็อกซี) ส่งคำขอที่เซิร์ฟเวอร์นี้ไม่เข้าใจ
KeyError: 'pw'

Traceback (โทรล่าสุดล่าสุด)

ไฟล์ "C: \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-package \ flask \ app.py" บรรทัด 2464 ในการโทร

ส่งคืน self.wsgi_app (สิ่งแวดล้อม start_response)

ไฟล์ "C: \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-Packages \ flask \ app.py" บรรทัด 2450 ใน wsgi_app

response = self.handle_exception (e)

ไฟล์ "C: \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-Packages \ flask \ app.py" บรรทัด 1867 ใน handle_exception

reraise (exc_type, exc_value, tb)

ไฟล์ "C: \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-Packages \ flask_compat.py" บรรทัดที่ 39 ใน reraise

เพิ่มมูลค่า

ไฟล์ "C: \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-Packages \ flask \ app.py" บรรทัด 2447 ใน wsgi_app

ตอบสนอง = self.full_dispatch_request ()

ไฟล์ "C: \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-Packages \ flask \ app.py" บรรทัด 1952 ใน full_dispatch_request

rv = self.handle_user_exception (จ)

ไฟล์ "C: \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-Packages \ flask \ app.py" บรรทัด 1821 ใน handle_user_exception

reraise (exc_type, exc_value, tb)

ไฟล์ "C: \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-Packages \ flask_compat.py" บรรทัดที่ 39 ใน reraise

เพิ่มมูลค่า

ไฟล์ "C: \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-Packages \ flask \ app.py" บรรทัด 1950 ใน full_dispatch_request

rv = self.dispatch_request ()

ไฟล์ "C: \ Users \ franc \ AppData \ Local \ Programs \ Python \ Python38-32 \ Lib \ site-Packages \ flask \ app.py" บรรทัด 1936 ใน dispatch_request

ส่งคืน self.view_functionsrule.endpoint

ไฟล์ "C: \ Users \ franc \ OneDrive \ Desktop \ Blog_Project \ blog_prova.py" บรรทัด 102 ในการเข้าสู่ระบบ

user.id = ชื่อผู้ใช้
flask_login.login_user (ผู้ใช้)
ส่งคืนการเปลี่ยนเส้นทาง (url_for ("add"))
else:
error = "Leider haben Sie die falschen Zugangsdaten"
ส่งคืน render_template ("login.html", error = error)
ส่งคืน render_template ("login.html")

รหัส:

@app.route('/add')

@login_required

File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask\templating.py", line 136, in render_template

ctx.app.update_template_context(context)

File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask\app.py", line 838, in update_template_context

context.update(func())

File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask_login\utils.py", line 379, in _user_context_processor

return dict(current_user=_get_user())

File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask_login\utils.py", line 346, in _get_user

current_app.login_manager._load_user()

File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask_login\login_manager.py", line 331, in _load_user

user = self._load_user_from_request(request)

File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\flask_login\login_manager.py", line 390, in _load_user_from_request

user = self._request_callback(request)

File "C:\Users\franc\OneDrive\Desktop\Blog_Project\blog_prova.py", line 85, in request_loader

    username = request.form.get("username")  # comunica col template <input ...name = "username"> Username </input>

    if username not in users:

        return

    user = User()

    user.id = username

    user.is_authenticated = request.form["pw"] == users[username]["pw"]

 

    return user

 

 

@app.route('/login', methods=["POST", "GET"])

File "C:\Users\franc\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\werkzeug\datastructures.py", line 442, in __getitem__

raise exceptions.BadRequestKeyError(key)

werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
KeyError: 'pw'

ดีบักเกอร์พบข้อยกเว้นในแอปพลิเคชัน WSGI ของคุณ ตอนนี้คุณสามารถดูการย้อนกลับซึ่งนำไปสู่ข้อผิดพลาดได้

หากต้องการสลับระหว่างการย้อนกลับแบบโต้ตอบและข้อความธรรมดาคุณสามารถคลิกที่บรรทัดแรก "Traceback" จากการย้อนกลับข้อความคุณยังสามารถสร้างการวางได้ สำหรับการเรียกใช้โค้ดวางเมาส์เหนือเฟรมที่คุณต้องการแก้จุดบกพร่องและคลิกที่ไอคอนคอนโซลทางด้านขวา

คุณสามารถรันโค้ด Python ได้ตามอำเภอใจในสแต็กเฟรมและมีตัวช่วยเพิ่มเติมสำหรับการวิปัสสนา:

dump() shows all variables in the frame
dump(obj) dumps all that's known about the object

Edit: If I run the Pycharm debugger, it seems that there are some problems with the method is_authenticated (Property 'is_authenticated' cannot be set). I don´t know if it is somehow inherent.

This is my sample code: 


```
from datetime import datetime
import flask_login
import yaml
from flask import Flask, render_template, request, redirect, url_for 
from flask_login import LoginManager, UserMixin, login_required, logout_user
from flask_sqlalchemy import SQLAlchemy


app = Flask(__name__)
app.config['TESTING'] = False
app.config['SECRET_KEY'] = 'chiavesegreta'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////Users/Desktop/Blog_Project/blog2.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

login_manager = LoginManager()
login_manager.init_app(app)


# {"Franz":{"pw":"Biberkopf"}}
with open(r'C://Users//Desktop//application.yaml') as file:
    users = yaml.full_load(file)


class User(UserMixin):
    pass


class Blogpost2(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(50))
    subtitle = db.Column(db.String(50))
    author = db.Column(db.String(20))
    date_posted = db.Column(db.DateTime)
    content = db.Column(db.Text)

db.create_all()


@app.route('/')
def index():
    posts = Blogpost2.query.order_by(Blogpost2.date_posted.desc()).all()

    return render_template('index.html', posts=posts)


@app.route('/about')
def about():
    return render_template('about.html')


@app.route('/post/<int:post_id>')
def post(post_id):
    post = Blogpost2.query.filter_by(id=post_id).one() 

    date_posted = post.date_posted.strftime('%d %B, %Y')

    return render_template('post.html', post=post, date_posted=date_posted)


@login_manager.user_loader
def user_loader(username):
    if username not in users:
        return

    user = User()
    user.id = username
    return user


@login_manager.request_loader
def request_loader(request):
    username = request.form.get("username")  
    if username not in users:
        return
    user = User()
    user.id = username
    user.is_authenticated = request.form["pw"] == users[username]["pw"]

    return user


@app.route('/login', methods=["POST", "GET"])
def login():
    error = None
    if request.method == 'POST':
        username = request.form.get('username')
        if request.form.get('pw') == users[username]["pw"]:
            user = User()
            user.id = username
            flask_login.login_user(user)
            return redirect(url_for("add"))
        else:
            error = "Leider haben Sie die falschen Zugangsdaten."
            return render_template("login.html", error=error)
    return render_template("login.html")


@app.route('/add')
@login_required
def add():
    return render_template('add.html')


@app.route('/logout')
def logout():
    logout_user()
    return "Logged out !"



@app.route('/contact')
def contact():
    return render_template('contact.html')


@app.route('/prova')
def prova():
    return render_template('prova.html')


@app.route('/addpost', methods=['POST'])
def addpost():
    title = request.form['title']
    subtitle = request.form['subtitle']
    author = request.form["author"]
    content = request.form['content']

    post = Blogpost2(title=title, subtitle=subtitle, author=author, content=content, date_posted=datetime.now())

    db.session.add(post)
    db.session.commit()

    return redirect(url_for('index'))


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


แนวคิดก็คือหากมีคนพยายามเข้าสู่ระบบโดยไม่มีชื่อผู้ใช้และรหัสผ่านที่ถูกต้องจะมีข้อความแสดงข้อผิดพลาดปรากฏขึ้น ด้วยข้อมูลรับรองที่ถูกต้องคุณสามารถเข้าถึงหน้า "เพิ่ม" ได้ ที่นี่หน้า login.html ของฉัน:

<!DOCTYPE html>
<html lang="en">

<head>

  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta name="description" content="">
  <meta name="author" content="">

  <title>Clean Blog - Start Bootstrap Theme</title>

  <!-- Bootstrap core CSS -->
  <!-- <link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet"> -->
  <link href= "{{ url_for('static', filename='bootstrap.min.css')}}" rel="stylesheet">

  <!-- Custom fonts for this template -->
  <!--  <link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">                              -->
  <link href="{{url_for('static', filename = 'fontawesome.min.css')}}" rel="stylesheet" type="text/css">
  <link href='https://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic' rel='stylesheet' type='text/css'>
  <link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css'>

  <!-- Custom styles for this template -->
  <link href="{{url_for('static', filename = 'clean-blog.min.css')}}" rel="stylesheet">

</head>

<body>

   <!-- Navigation -->
  <nav class="navbar navbar-expand-lg navbar-light fixed-top" id="mainNav">
    <div class="container">
      <a class="navbar-brand" href= "{{ url_for('index') }}">Start Bootstrap</a>
      <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
        Menu
        <i class="fas fa-bars"></i>
      </button>
      <div class="collapse navbar-collapse" id="navbarResponsive">
        <ul class="navbar-nav ml-auto">
          <li class="nav-item">
            <a class="nav-link" href="{{ url_for('index')}}">Home</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="{{ url_for('about')}}">About</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="{{ url_for('contact')}}">Contact</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="{{ url_for('prova')}}">Prova</a>
          </li>
        </ul>
      </div>
    </div>
  </nav>

  <!-- Page Header -->
  <header class="masthead" style="background-image: url('img/contact-bg.jpg')">
    <div class="overlay"></div>
    <div class="container">
      <div class="row">
        <div class="col-lg-8 col-md-10 mx-auto">
          <div class="page-heading">
            <h1>Login</h1>
          </div>
        </div>
      </div>
    </div>
  </header>



  <hr>

  <!-- Footer -->
  <footer><!-- Main Content -->
  <div class="container"> <!-- crea contenitore x la larghezza del layout -->
    <div class="row"> <!--  crea riga  -->
      <div class="col-lg-8 col-md-10 mx-auto"> <!-- crea colonna -->
        <p>Login zu dem privaten Area dieses Blogs</p>

        <form action = "" method = "POST" name="sentMessage" id="contactForm" novalidate>
          <div class="control-group">
            <div class="form-group floating-label-form-group controls">

              <label>Username</label>

                 <input name = "username" type="text" class="form-control" placeholder="Username" id="Username" required data-validation-required-message="Please enter your username." value ="{{ request.form.username }}">
                 <p class="help-block text-danger"></p>
                </div>
               </div>
          <div class="control-group">
            <div class="form-group floating-label-form-group controls">
              <label>Password</label>

              <input name= "pw"  class="input" placeholder="pw" id="pw" required data-validation-required-message="Please enter your password." value = "{{ request.form.pw }}">

              <p class="help-block text-danger"></p>
            </div>
          </div>

          <div class = "container">
          <div class = "row" >
          <input type = "checkbox" onclick = "Toggle()">

              <label> Show Password </label>

            <script>

                function Toggle() {
                var temp = document.getElementById("typepass");
                if (temp.type === "password") {
                temp.type = "text";
              }
                else {
                  temp.type = "password";
                }

              }

            </script>

          </div>
        </div>





          <br>
          <div id="success"></div>
          <button type="submit" class="btn btn-primary" id="sendMessageButton">Login!</button>
        </form>

        {% if error %}

        <p class = "error"> <strong> Error: </strong> {{ error }}

          {% endif %}

      </div>
    </div>
  </div>
    <div class="container">
      <div class="row">
        <div class="col-lg-8 col-md-10 mx-auto">
          <!-- Qua inizia la parte inferiore-->
          <p class="copyright text-muted">Copyright &copy; Your Website 2020</p>
        </div>
      </div>
    </div>
  </footer>



  <!-- Bootstrap core JavaScript -->
  <script src= "{{ url_for('static', filename = 'jquery.min.js')}}"> </script>
  <script src= "{{ url_for('static', filename = 'bootstrap.min.js')}}"></script>


  <!-- Custom scripts for this template -->
  <script src="{{ url_for('static', filename = 'clean-blog.min.js')}}"> </script>>

</body>

</html>

ฉันใหม่มากสำหรับทุกสิ่งและตอนนี้ฉันค่อนข้างติดขัดและสับสน ขอบคุณมากสำหรับทุกคำแนะนำ

คำตอบ

2 J.G. Oct 08 2020 at 22:53

ข้อผิดพลาดอาจเกิดจากโดยuser.is_authenticated = request.form["pw"] == users[username]["pw"]เฉพาะrequest.form["pw"]- สิ่งนี้พยายามเข้าถึงตัวแปร pw แต่สิ่งนี้ไม่ได้ถูกส่งโดยแบบฟอร์ม

อาจเกิดจากช่องว่างหลังเครื่องหมายเท่ากับ - input name= "pw

อันที่จริงฉันไม่แน่ใจ 100% เพราะฉันไม่เคยใช้พื้นที่ตรงนั้น เป็นแนวทางปฏิบัติที่ดีในการใช้ IDE ซึ่งจัดรูปแบบโค้ดอย่างถูกต้อง ด้วยรหัสที่ "สะอาด" และมีเสียงรบกวนน้อยกว่าจะทำให้เห็นข้อผิดพลาดได้ง่ายกว่าเสมอ

อัปเดต

ดูเหมือนว่าจะอนุญาตช่องว่าง: ใช้ช่องว่างก่อนและหลังเครื่องหมาย `=` ของแอตทริบิวต์องค์ประกอบ HTML

ปล: ข้อผิดพลาดอาจเกี่ยวข้องกับการใช้ request_loader ของคุณ ฉันเป็นผู้ใช้ flask-login จำนวนมากและไม่เคยใช้ request_loader ตามที่ระบุไว้เป็นรูปแบบพิเศษซึ่งคุณไม่จำเป็นต้องใช้

ขอแนะนำให้คุณอ่านเอกสารอีกครั้ง ( https://flask-login.readthedocs.io/en/latest/#custom-login-using-request-loader ) และดูบทช่วยสอนที่ยอดเยี่ยมนี้: https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world

อัปเดต 2

ฉันอ่านเอกสารการเข้าสู่ระบบขวด เมื่อคุณใช้ request_loader คุณจะต้องส่งข้อมูลการเข้าสู่ระบบพร้อมทุกคำขอ แต่คุณจะส่งเมื่อคุณกรอกแบบฟอร์มเท่านั้น

=> ตามที่กล่าวไว้ก่อนหน้านี้ อย่าใช้ตัวโหลดคำขอ ใช้เช่นล็อกอินตามคุกกี้ ดู Flask Login docu และบทช่วยสอนหลัก

1 simkusr Oct 08 2020 at 21:16

คุณควรมีฐานข้อมูลเพื่อจัดเก็บcontentบล็อก แล้วทำไมคุณถึงต้องการเปิดเผยใน. yaml ข้อมูลประจำตัวของคุณ (ไม่เคยเปิดเผยข้อมูลรับรองในไฟล์ที่รวมอยู่ในที่เก็บ git ด้วยเหตุผลทางประวัติศาสตร์) ฉันจะใช้เช่นflask_loginหรือflask_userและสร้างผู้ใช้ด้วยสคริปต์ในการผลิต (สภาพแวดล้อมอื่น ๆ ) เช่น

python create_account.py --username=username --password=password

ดังนั้นจึงไม่มีใครสามารถสร้างบัญชีได้จากนั้นการตรวจสอบชื่อผู้ใช้ / รหัสผ่านจะถูกจัดการโดยไลบรารีนั้นและคุณจะไม่เปิดเผย (ในกรณีที่มีบางคนสามารถเข้าถึงที่เก็บ git ของคุณได้)

อย่างน้อยฉันก็จะใช้แนวทางนี้