HTML <img>标签阻止ajax POST

时间:2019-07-22 18:48:57

标签: javascript html ajax

我正在使用Flask将视频流式传输到网页上。

  1. 视频流本身起作用。
  2. 然后,我添加了一个与python后端函数连接的模式,并获取要显示的数据。
  3. 模式显示从python函数返回的数据。
  4. 一旦我第一次激活html <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">&times;</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)

如何重现错误

  1. <img>中的templates/index.html标签目前已被注释掉:
<!--video feed, uncomment the <img> tag to reproduce error===-->

<!--<img id="vid" src="{{ url_for('video_feed') }}">-->

<!--video feed ==============================================-->
  1. 运行python app.py
  2. 在浏览器中打开localhost:5000,然后单击open modal,您应该看到get_data.py返回的工作状态的客户信息。
  3. 使用Ctrl+C停止Flask服务器。取消注释<img>中的templates/index.html标签,然后将相机连接到PC并第二次运行python app.py。单击open modal,将无法获取在模态中创建表的数据。

预期结果是在流式传输视频时显示模态内容。当前,显示结果的唯一方法是禁用<img>标签,谢谢。

1 个答案:

答案 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">&times;</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>

希望这对其他人有帮助。