我正在使用Flask将视频流式传输到网页上。
<img>
标签流式传输视频和模态,视频流就会阻止ajax POST,因此模态无法显示数据。条件4)失败。似乎<img>
标签阻止了ajax POST。
此代码是我几天前提交并回答的先前帖子的延续 https://stackoverflow.com/questions/57067923/returned-python-values-break-html-table-after-inserting-in-javascript-array
这是一个完整的代码,可以重现我的错误,谢谢。
# project/get_data.py: python backend module that return data to be displayed in a modal table
class GetData:
def __init__(self):
pass
def records(self):
return [(1, 'John Smith', 'Canada'),
(2, 'Jane Doe', 'United States'),
(3, 'John Doe', 'Mexico')]
# project/camera.py : camera module that returns encoded frames
import cv2
class VideoCamera(object):
def __init__(self):
self.video = cv2.VideoCapture(0)
def __del__(self):
self.video.release()
def get_frame(self):
ret, frame = self.video.read()
if ret:
ret, jpeg = cv2.imencode('.jpg', frame)
return jpeg.tobytes()
<!-- project/templates/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
body {font-family: Arial, Helvetica, sans-serif;}
/* The Modal (background) */
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 1; /* Sit on top */
padding-top: 100px; /* Location of the box */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}
/* Modal Content */
.modal-content {
background-color: #fefefe;
margin: auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
}
/* The Close Button */
.close {
color: #aaaaaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
</style>
</head>
<body>
<!-- Trigger/Open The Modal -->
<button id="myBtn">Open Modal</button>
<!-- The Modal -->
<div id="myModal" class="modal">
<!-- Modal content -->
<div class="modal-content">
<span class="close">×</span>
<div id="dvTable"></div>
</div>
</div>
<style>
table {
font-family: arial, sans-serif;
border-collapse: collapse;
width: 100%;
}
td, th {
border: 1px solid #dddddd;
text-align: left;
padding: 8px;
}
tr:nth-child(even) {
background-color: #dddddd;
}
</style>
<br><br>
<!--video feed, uncomment the <img> tag to reproduce error===-->
<!--<img id="vid" src="{{ url_for('video_feed') }}">-->
<!--video feed ==============================================-->
<script src="https://code.jquery.com/jquery-3.4.1.js"
integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU="
crossorigin="anonymous">
</script>
<script>
// Get the modal
var modal = document.getElementById("myModal");
// Get the button that opens the modal
var btn = document.getElementById("myBtn");
// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];
// When the user clicks the button, open the modal
btn.onclick = function() {
modal.style.display = "block";
//var Table = document.getElementById("dvTable").innerHTML = "";
$("#dvTable tr").remove();
$.ajax({
url: "/_get_data/",
type: "POST",
success: function(resp){
$('div#dvTable').append(resp.data);
}
});
}
// When the user clicks on <span> (x), close the modal
span.onclick = function() {
modal.style.display = "none";
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
</script>
</body>
</html>
<!--project/templates/response.html-->
<table>
<tr>
<th>Customer Id</th>
<th>Name</th>
<th>Country</th>
</tr>
{% for elem in myList %}
<tr>
<td>{{elem[0]}}</td>
<td>{{elem[1]}}</td>
<td>{{elem[2]}}</td>
</tr>
{% endfor %}
</table>
# project/app.py : flask framework
from flask import Flask, render_template, Response, jsonify
from camera import VideoCamera
from get_data import GetData
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/_get_data/', methods=['POST'])
def _get_data():
data = GetData()
myList = data.records()
return jsonify({'data': render_template('response.html', myList=myList)})
def gen(camera):
"""Video streaming generator function."""
while True:
frame = camera.get_frame()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')
@app.route('/video_feed')
def video_feed():
"""Video streaming route. Put this in the src attribute of an img tag."""
return Response(gen(VideoCamera()),
mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == "__main__":
app.run(debug=True)
如何重现错误
<img>
中的templates/index.html
标签目前已被注释掉:<!--video feed, uncomment the <img> tag to reproduce error===-->
<!--<img id="vid" src="{{ url_for('video_feed') }}">-->
<!--video feed ==============================================-->
python app.py
open modal
,您应该看到get_data.py
返回的工作状态的客户信息。Ctrl+C
停止Flask服务器。取消注释<img>
中的templates/index.html
标签,然后将相机连接到PC并第二次运行python app.py
。单击open modal
,将无法获取在模态中创建表的数据。预期结果是在流式传输视频时显示模态内容。当前,显示结果的唯一方法是禁用<img>
标签,谢谢。
答案 0 :(得分:0)
我找到了解决此问题的方法: 1)更新到flask到1.1.1可以解决此问题,而无需更改代码。
2)另一种解决方案是放弃ajax请求和from distutils.core import setup, Extension
from Cython.Build import cythonize
setup(ext_modules = cythonize(Extension(
"app",
sources=["app.pyx", "myapp.cpp"],
language="c++",
include_dirs=["../base"]
)))
并进行以下更改:
template.html
<!-- project/templates/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
body {font-family: Arial, Helvetica, sans-serif;}
/* The Modal (background) */
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 1; /* Sit on top */
padding-top: 100px; /* Location of the box */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}
/* Modal Content */
.modal-content {
background-color: #fefefe;
margin: auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
}
/* The Close Button */
.close {
color: #aaaaaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
</style>
</head>
<body>
<!-- OPEN THE CONTENT WHEN USER CLICKS MODAL-->
<button id="myBtn" onclick="document.getElementById('myModal').style.display='block'">Open Modal</button>
<!-- The Modal -->
<div id="myModal" class="modal">
<!-- Modal content -->
<div class="modal-content">
<span class="close">×</span>
<div id="dvTable">
<!-- INSERT THE TABLE IN THE MODAL-->
<table>
<table>
<tr>
<th>Customer Id</th>
<th>Name</th>
<th>Country</th>
</tr>
<tr>
<!-- loop through data -->
{% for elem in myList %}
<tr>
<td>{{elem[0]}}</td>
<td>{{elem[1]}}</td>
<td>{{elem[2]}}</td>
</tr>
{%endfor %}
</tr>
</table>
</table>
</div>
</div>
</div>
<style>
table {
font-family: arial, sans-serif;
border-collapse: collapse;
width: 100%;
}
td, th {
border: 1px solid #dddddd;
text-align: left;
padding: 8px;
}
tr:nth-child(even) {
background-color: #dddddd;
}
<br><br>
</style>
<img id="bg" src="{{ url_for('video_feed') }}">
<!--<script src="https://code.jquery.com/jquery-3.4.1.js"
integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU="
crossorigin="anonymous">
</script>-->
<script>
// Get the modal
var modal = document.getElementById("myModal");
// Get the button that opens the modal
var btn = document.getElementById("myBtn");
// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];
//AJAX POST COMMENTED OUT
/*
// When the user clicks the button, open the modal
btn.onclick = function() {
modal.style.display = "block";
//var Table = document.getElementById("dvTable").innerHTML = "";
$("#dvTable tr").remove();
$.ajax({
url: "/_get_data/",
type: "POST",
success: function(resp){
$('div#dvTable').append(resp.data);
}
});
}
*/
// When the user clicks on <span> (x), close the modal
span.onclick = function() {
modal.style.display = "none";
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
</script>
</body>
</html>
希望这对其他人有帮助。