0

0

解决Flask应用中“URL未找到”错误与安全更新用户密码的教程

碧海醫心

碧海醫心

发布时间:2025-09-28 11:10:16

|

316人浏览过

|

来源于php中文网

原创

解决Flask应用中“URL未找到”错误与安全更新用户密码的教程

本教程详细讲解了在Flask应用中处理“URL未找到”错误,特别是由于Jinja模板变量语法错误导致的404问题。文章通过修正HTML表单的action属性,并优化Flask后端代码,演示了如何安全地更新用户密码、正确处理数据库事务、实现密码哈希以及恰当进行页面重定向,确保用户体验和系统安全。

1. 理解“URL未找到”错误及其根源

在开发web应用时,"the requested url was not found on the server" (http 404 not found) 是一个常见的错误。当用户尝试访问的url与服务器上定义的任何路由都不匹配时,就会出现此错误。在flask应用中,这通常意味着:

  • 路由未定义: 在@app.route()装饰器中没有定义与请求URL匹配的路径。
  • URL拼写错误: 用户或模板中生成的URL与实际定义的路由不符。
  • 动态URL参数错误: 当URL包含动态部分(如/update/)时,如果模板未能正确渲染这些动态参数,生成的URL就会不匹配。

本教程中的问题即属于第三种情况:HTML表单的action属性未能正确地将动态ID变量嵌入到URL中。

2. Jinja2 模板变量渲染:核心问题与解决方案

在Flask应用中,我们通常使用Jinja2作为模板引擎。Jinja2有其特定的语法来渲染Python变量到HTML中。问题的核心在于HTML表单的action属性中对变量id的引用方式:

原始错误代码:

{{ form.password(class="form-control", value=userPass.password) }} {{ form.submit}}

这里的action="/update/{id}"使用了Python f-string或占位符的语法,而不是Jinja2的变量渲染语法。Jinja2模板引擎在处理模板时,并不会将{id}解析为变量。因此,生成的URL会是字面量/update/{id},而不是期望的/update/1或/update/123。

正确解决方案: Jinja2使用双大括号{{ variable }}来表示要渲染的变量。因此,正确的action属性应为:

{# ... 表单字段 ... #}

注意: 在这里,我们假设从后端传递到模板的userPass变量已被更名为user,以提高可读性。{{ user.id }}将确保id的实际值被正确地插入到URL中,从而匹配Flask的/update/路由。

此外,在密码更新表单中,value=userPass.password是一个严重的安全隐患。如果userPass.password存储的是哈希后的密码,将其直接显示在表单中会暴露哈希值;如果存储的是明文密码,那更是不可接受。密码输入框通常不应该预填充任何值,尤其不应预填充密码本身。应将其移除或设为空。

Manus
Manus

全球首款通用型AI Agent,可以将你的想法转化为行动。

下载

3. Flask 路由与后端逻辑优化:安全更新密码

解决了前端URL生成问题后,我们还需要优化Flask后端的逻辑,以确保密码更新过程是安全、健悦且用户友好的。

3.1 路由定义与参数获取

Flask的路由定义@app.route('/update/', methods=['GET', 'POST'])非常标准。表示id是一个整数类型的动态参数,它将被传递给update视图函数。

3.2 后端代码改进要点

  1. 密码哈希: 绝不能以明文形式存储用户密码。在保存新密码之前,必须对其进行哈希处理。werkzeug.security模块提供了generate_password_hash函数。
  2. 表单验证: 建议使用Flask-WTF等库来创建表单,它能提供强大的表单验证功能(如密码强度、确认密码等)。form.validate_on_submit()方法可以同时处理POST请求和表单验证。
  3. 数据库事务: 在修改数据库时,使用try...except...finally块来确保事务的原子性。如果发生错误,应回滚事务以防止数据不一致。
  4. 重定向与渲染: return render_template(...)和redirect(url_for(...))是两种不同的响应方式。render_template是渲染一个页面并返回,而redirect是告诉浏览器去访问另一个URL。它们不能在同一个分支中同时执行,redirect后面的代码将永远不会被执行。成功操作后应重定向到其他页面(如登录页),失败时可以重新渲染当前页面并显示错误信息。
  5. 权限检查: 在更新用户数据时,务必检查当前登录用户是否有权限修改目标用户的数据,防止恶意篡改。

3.3 优化后的Flask后端代码示例

from flask import Flask, render_template, request, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy
from flask_login import login_required, current_user # 假设使用了Flask-Login
from werkzeug.security import generate_password_hash, check_password_hash # 用于密码哈希和验证
from flask_wtf import FlaskForm
from wtforms import PasswordField, SubmitField
from wtforms.validators import DataRequired, EqualTo, Length

# 假设 app, db, User 模型已经定义
# 例如:
# app = Flask(__name__)
# app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
# db = SQLAlchemy(app)
#
# class User(db.Model):
#     id = db.Column(db.Integer, primary_key=True)
#     username = db.Column(db.String(20), unique=True, nullable=False)
#     password = db.Column(db.String(128), nullable=False) # 存储哈希后的密码

# 示例:更新密码表单 (使用Flask-WTF)
class UpdatePasswordForm(FlaskForm):
    password = PasswordField('新密码', validators=[DataRequired(), Length(min=6)])
    confirm_password = PasswordField('确认新密码', validators=[DataRequired(), EqualTo('password', message='两次输入的密码不一致!')])
    submit = SubmitField('更新密码')

# 示例:假设您有登录功能和用户模型
# @login_manager.user_loader
# def load_user(user_id):
#     return User.query.get(int(user_id))

@app.route('/update/', methods=['GET', 'POST'])
@login_required # 确保用户已登录
def update(id):
    # 安全检查:确保当前登录用户只能修改自己的密码
    if current_user.id != id:
        flash("您无权修改其他用户的密码。", "warning")
        return redirect(url_for('dashboard')) # 重定向到用户仪表盘或其他合适页面

    form = UpdatePasswordForm()
    user_to_update = User.query.get_or_404(id) # 如果用户不存在,则返回404

    if form.validate_on_submit(): # 处理POST请求且表单验证通过
        # 1. 哈希新密码
        hashed_password = generate_password_hash(form.password.data, method='pbkdf2:sha256') # 推荐使用更强的哈希算法
        user_to_update.password = hashed_password

        try:
            db.session.commit() # 提交数据库更改
            flash("密码更新成功!请使用新密码登录。", "success")
            return redirect(url_for('login')) # 成功后重定向到登录页
        except Exception as e:
            db.session.rollback() # 发生错误时回滚事务
            flash(f"错误:更新密码时发生问题。请重试。详细信息: {e}", "danger")
            # 错误时,重新渲染页面,让用户可以修正并重试
            return render_template("update.html", form=form, user=user_to_update)

    # 对于GET请求或POST请求但表单验证失败的情况
    return render_template("update.html", form=form, user=user_to_update)

# 示例:一个简单的仪表盘路由,用于重定向
@app.route('/dashboard')
@login_required
def dashboard():
    return render_template('dashboard.html', user=current_user)

# 示例:登录路由,用于重定向
@app.route('/login', methods=['GET', 'POST'])
def login():
    # ... 登录逻辑 ...
    return render_template('login.html')

4. 优化后的HTML模板示例

根据上述后端代码的优化,前端模板也需要进行相应调整,包括正确的Jinja2变量渲染、显示Flash消息和CSRF令牌(如果使用Flask-WTF)。




    
    
    
    更新密码
    
    


    

更新密码

{# 显示Flash消息 #} {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %}
    {% for category, message in messages %}
  • {{ message }}
  • {% endfor %}
{% endif %} {% endwith %} {# 注意:action="/update/{{ user.id }}" 是修正后的关键点 #}
{{ form.csrf_token }} {# Flask-WTF会自动生成CSRF令牌 #}
{{ form.password.label(class="form-label") }} {{ form.password(class="form-control", placeholder="输入新密码", required=true) }} {% if form.password.errors %}
{% for error in form.password.errors %} {{ error }} {% endfor %}
{% endif %}
{{ form.confirm_password.label(class="form-label") }} {{ form.confirm_password(class="form-control", placeholder="再次输入新密码", required=true) }} {% if form.confirm_password.errors %}
{% for error in form.confirm_password.errors %} {{ error }} {% endfor %}
{% endif %}
{{ form.submit(class="btn btn-primary mt-3") }}

5. 注意事项与最佳实践

  • Jinja2 变量语法: 始终记住使用{{ variable }}来在Jinja2模板中渲染Python变量。对于控制结构(如循环、条件),使用{% control_statement %}。
  • 密码哈希: 这是任何用户认证系统的基石。不要存储明文密码。选择一个强大的哈希算法(如pbkdf2:sha256或bcrypt)。
  • Flask-WTF: 强烈推荐使用Flask-WTF来处理Web表单。它简化了表单定义、验证和CSRF保护。
  • 重定向与渲染: 理解render_template()和redirect(url_for())的区别。成功操作后通常重定向以防止表单重复提交(Post/Redirect/Get模式),失败时通常重新渲染当前页面并显示错误信息。
  • 权限管理: 对于敏感操作(如更新密码、删除账户),务必在后端进行严格的权限检查,确保用户只能操作自己的数据或拥有相应权限。
  • 错误处理: 使用try...except块捕获数据库操作或其他可能发生的错误,并提供有意义的用户反馈。在数据库操作失败时,务必调用db.session.rollback()。
  • Flash 消息: 利用flash()函数向用户提供临时的反馈信息(成功、警告、错误),并通过模板中的get_flashed_messages()显示。
  • 用户体验: 在表单中提供清晰的标签、占位符和错误提示,引导用户正确操作。

通过遵循这些指南,您可以构建一个更健壮、安全且用户友好的Flask应用程序。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Python Flask框架
Python Flask框架

本专题专注于 Python 轻量级 Web 框架 Flask 的学习与实战,内容涵盖路由与视图、模板渲染、表单处理、数据库集成、用户认证以及RESTful API 开发。通过博客系统、任务管理工具与微服务接口等项目实战,帮助学员掌握 Flask 在快速构建小型到中型 Web 应用中的核心技能。

86

2025.08.25

Python Flask Web框架与API开发
Python Flask Web框架与API开发

本专题系统介绍 Python Flask Web框架的基础与进阶应用,包括Flask路由、请求与响应、模板渲染、表单处理、安全性加固、数据库集成(SQLAlchemy)、以及使用Flask构建 RESTful API 服务。通过多个实战项目,帮助学习者掌握使用 Flask 开发高效、可扩展的 Web 应用与 API。

72

2025.12.15

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

463

2023.08.02

session失效的原因
session失效的原因

session失效的原因有会话超时、会话数量限制、会话完整性检查、服务器重启、浏览器或设备问题等等。详细介绍:1、会话超时:服务器为Session设置了一个默认的超时时间,当用户在一段时间内没有与服务器交互时,Session将自动失效;2、会话数量限制:服务器为每个用户的Session数量设置了一个限制,当用户创建的Session数量超过这个限制时,最新的会覆盖最早的等等。

315

2023.10.17

session失效解决方法
session失效解决方法

session失效通常是由于 session 的生存时间过期或者服务器关闭导致的。其解决办法:1、延长session的生存时间;2、使用持久化存储;3、使用cookie;4、异步更新session;5、使用会话管理中间件。

751

2023.10.18

cookie与session的区别
cookie与session的区别

本专题整合了cookie与session的区别和使用方法等相关内容,阅读专题下面的文章了解更详细的内容。

93

2025.08.19

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

463

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

544

2024.08.29

java入门学习合集
java入门学习合集

本专题整合了java入门学习指南、初学者项目实战、入门到精通等等内容,阅读专题下面的文章了解更多详细学习方法。

1

2026.01.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Sass 教程
Sass 教程

共14课时 | 0.8万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.1万人学习

CSS教程
CSS教程

共754课时 | 25万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号