【问题标题】:Flask-SocketIO making sure socket disconnects from client correctlyFlask-SocketIO 确保套接字正确地与客户端断开连接
【发布时间】:2020-05-20 18:55:44
【问题描述】:

我将 Flask-SocketIO 库添加到我的 Flask 应用程序以处理实时连接并在用户完成特定操作后使用发送到后端的 cookie 对其进行测试。这是为了防止用户在向 URL 发出另一个 HTTP 请求之前关闭他们的浏览器或网页。我发现浏览器不会在 javascript 中保存使用 document.cookie 设置的 cookie,直到它从服务器接收到 cookie 作为响应。由于添加了 WebSocket 并在开发环境中对其进行了测试,因此套接字确实正确地发出了 cookie。但是,当我尝试在终端中使用 ctrl-C 时,它不会触发信号,即使在我关闭终端和浏览器/网页之后,localhost 仍在侦听端口。我知道如何使用taskkill 手动终止该进程,但我担心的是,与客户端的套接字连接在他们已经关闭网页/浏览器后仍处于打开状态。我假设这可能对后端性能不利,并可能导致一些安全风险,尽管我不确定。这可能是因为我没有正确处理套接字连接并在后端发出消息,但那是因为文档中的示例代码难以理解。这是文档:https://flask-socketio.readthedocs.io/en/latest/。

有人可以回答这个问题吗?

__init__.py:

from flask import Flask, url_for, current_app
from flask_socketio import SocketIO

csp = {
    "default-src": [
        "'self'",
        'https://www.youtube.com'
    ],
    'script-src': [ "'self'",
                    'https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js',
                    'https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js',
                    'https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js'],
    'style-src': ["'self'",
                  'https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css'],
    'img-src': ["'self'",
                'data:',
                'https://i.ytimg.com' ],
    'font-src': ['data:']
}

config = {
    "CACHE_TYPE": "simple",
    "DEBUG": True,
    "SQLALCHEMY_DATABASE_URI": "sqlite:///site.db",
    "SQLALCHEMY_TRACK_MODIFICATIONS": False,
    "SQLALCHEMY_ECHO": False
}
socketio = SocketIO()
def create_app():
    app = Flask(__name__)
    app.config.from_mapping(config)
    socketio.init_app(app)

    from flask_app.main.routes import main
    app.register_blueprint(main)
    with app.app_context():
        db.create_all()
        socketio.run(current_app)

    return app

main/routes.py:

from flask import render_template, session, request, current_app, Blueprint, redirect, url_for, json, make_response
from flask_app import cache
import os

main = Blueprint("main", __name__)

@main.route("/")
def index():
    return render_template("index.html", title="Home")

@main.context_processor
def inject_template_scope():
    injections = dict()

    # Use this method to check if the client has consented to the use of cookies.
    def cookies_check():
        value = request.cookies.get('consent')
        return value != None
    injections.update(cookies_check=cookies_check)
    return injections

运行.py:

from flask_app import create_app

base.html:

<html>
 <body>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"
    integrity="sha256-yr4fRk/GU1ehYJPAs8P4JlTgu0Hdsp4ZKrx8bDEDC3I="
    crossorigin="anonymous"></script>
 </body>
</html>

base.js:

$(window).on('load', function() {
 function cookieConsent() {
   var socket = io();
   const now = new Date();
   document.cookie = "consent=consented:true,dateTime:" + now + ",lang:" + navigator.language;
   socket.on('connect', function() {
       socket.emit('consent cookie', {consent_cookie: document.cookie});
   });
 }
}

项目层次结构:

project/
|_ flask_app/
   |_ main/
      |_ routes.py
   |_ templates/
      |_ base.html
   |_ static/
      |_ js/
         |_ base.js
   |_ __init__.py
|_ run.py

环境变量:

FLASK_APP : run.py
FLASK_ENV : development

【问题讨论】:

  • 您能分享一下您是如何运行您的应用程序的吗?
  • 我刚刚用我的项目层次结构和环境变量更新了我的帖子,在我的终端中的项目/目录路径中我运行命令flask run。

标签: python flask flask-socketio


【解决方案1】:

socketio.run(app)在5000端口启动一个开发服务器。

所以当你执行flask runflask 调用函数create_app() 并期待一个应用程序。但是,您的函数实际上并没有返回 app,因为 socketio.run(app) 正在阻塞。当你按下 CTRL+C 时,它会停止这一行。

【讨论】:

  • 我刚刚用我的项目层次结构和环境变量更新了我的帖子,在我的终端中的项目/目录路径中运行命令flask run。 Flask 通过查找由FLASK_APP 环境变量设置的启动文件(这是run.py)工作,并在flask_app 目录中查找它,然后执行该文件。 _init_.py 文件被执行,由于run.py 导入了create_app() 函数,它被调用。我对python的所有事情都不是很精通,但这似乎很有效,所以我想你不需要直接调用方法。
  • flask run 进行函数调用,但您的函数不返回 app.相反,它会启动一个开发服务器。
  • 好的,所以我应该直接调用create_app() 函数并返回应用程序,然后将其发送到socketio.run()?我更新了我的 run.py 代码,这是启动套接字的正确方法,以便在我向终端发送 SIGTERM 时可以终止它吗?
  • 我会那样做。 Flask 默认使用 werkzeug 作为开发服务器(当你运行 flask run 时)。看起来他们不得不创建他们的嵌入式服务器(我不知道 werkzeug 可能不支持 WebSockets)。他们在文档的部署部分简要提到了嵌入式服务器。
  • 我发现问题出在 python 包 eventlet 上。 Flak_SocketIO 文档声明要安装 eventlet 或 event 以将 socketio 用于生产目的。我使用 gunicorn 和 Nginx 在 Heroku 上为我的应用程序提供服务,因此使用 gunicorn 并将必要的信息添加到 Nginx 配置文件是有意义的。但是在我的环境中安装了 eventlet,它不允许使用 CTRL + C。卸载 eventlet 后,一切似乎在开发中都可以正常工作
猜你喜欢
  • 1970-01-01
  • 2019-05-30
  • 2022-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-20
  • 1970-01-01
相关资源
最近更新 更多