Flask人脸识别跳转调用url_for报应用上下文缺失RuntimeError
问题原因
首先明确你的报错和逻辑问题:
- 你调用
url_for、redirect的位置在gen_frames生成器函数内,该函数作为视频流响应的内容源运行时,没有携带Flask应用上下文,所以直接触发RuntimeError: Attempted to generate a URL without the application context being pushed报错。 - 即使你解决了上下文报错,此处的跳转逻辑也不可能生效:视频流的响应类型为
multipart/x-mixed-replace,仅用于给页面上的<img>标签提供实时画面,浏览器不会把该响应中的302跳转指令当做整页跳转处理。
解决方案
需要调整为后端存储认证状态+前端轮询触发跳转的逻辑,修改如下:
1. 调整后端代码(app.py)
from flask import Flask, render_template, request, redirect, url_for, session, Response, jsonify import re import cv2 import numpy as np import face_recognition # 初始化Flask app = Flask(__name__) # 必须设置secret_key才能使用session app.secret_key = '自定义你的密钥字符串' # 人脸识别相关初始化代码保持不变 bechkam_image = face_recognition.load_image_file("Bechkam/beckham.jpg") bechkam_face_encoding = face_recognition.face_encodings(bechkam_image)[0] rooney_image = face_recognition.load_image_file("Rooney/rooney.jpg") rooney_face_encoding = face_recognition.face_encodings(rooney_image)[0] with open('label.txt') as f: lines = f.read() kn_fc_nm = lines.split(',') known_face_encodings = [ bechkam_face_encoding, rooney_face_encoding ] known_face_names = kn_fc_nm face_locations = [] face_encodings = [] face_names = [] process_this_frame = True def gen_frames(): camera = cv2.VideoCapture(0, cv2.CAP_DSHOW) while True: success, frame = camera.read() if not success: break else: small_frame = cv2.resize(frame, (0,0), fx=0.25, fy=0.25) rgb_small_frame = small_frame[:, :, ::-1] face_locations = face_recognition.face_locations(rgb_small_frame) face_encodings = face_recognition.face_encodings( rgb_small_frame, face_locations) face_names = [] auth = [] for face_encoding in face_encodings: matches = face_recognition.compare_faces( known_face_encodings, face_encoding) name = "Unknown" face_distances = face_recognition.face_distance( known_face_encodings, face_encoding) best_match_index = np.argmin(face_distances) if matches[best_match_index]: name = known_face_names[best_match_index] face_names.append(name) if face_names[0] in known_face_names: print("访问通过") # 存储认证状态到session session['authenticated'] = True # 释放摄像头资源后退出生成器 camera.release() cv2.destroyAllWindows() return elif face_names[0] == "Unknown": print('未知身份') else: print('身份未录入') for (top, right, bottom, left), name in zip(face_locations, face_names): top *= 4 right *= 4 bottom *= 4 left *= 4 cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2) cv2.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255), cv2.FILLED) font = cv2.FONT_HERSHEY_DUPLEX cv2.putText(frame, name, (left + 6, bottom - 6), font, 1.0, (255, 255, 255), 1) ret, buffer = cv2.imencode('.jpg', frame) frame = buffer.tobytes() yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n') # 新增认证状态查询接口 @app.route('/check_auth') def check_auth(): return jsonify({'authenticated': session.get('authenticated', False)}) @app.route('/video_feed') def video_feed(): # 每次进入刷脸页面重置认证状态 session['authenticated'] = False return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame') @app.route('/home') def home(): return render_template('home.html') @app.route('/face_login') def face_login(): return render_template('face.html') if __name__ == '__main__': app.run(debug=True)
2. 调整前端页面(face.html)
在face.html中添加轮询逻辑,检测到认证成功后自动跳转:
<!-- 原有页面代码保持不变,新增以下JS代码 --> <script> // 每1秒查询一次认证状态 setInterval(() => { fetch('/check_auth') .then(res => res.json()) .then(data => { if(data.authenticated){ window.location.href = '/home' } }) }, 1000) </script>
临时测试上下文问题的方案(不推荐,仅用于理解报错原因)
如果仅想解决上下文报错,不需要跳转生效,可以在调用url_for前手动推入应用上下文:
with app.app_context(): return redirect(url_for('home'))
该方案仅能消除报错,无法实现页面跳转的业务需求。
内容的提问来源于stack exchange,提问作者Renol N
相关产品推荐
相关产品推荐

