【Azure 应用服务】App Service for Linux 中实现 WebSocket 功能 (Python SocketIO)

简介: 【Azure 应用服务】App Service for Linux 中实现 WebSocket 功能 (Python SocketIO)

问题描述

使用 python websockets 模块作为Socket的服务端,发布到App Service for Linux环境后,发现Docker Container无法启动。错误消息为:

2021-10-28T02:39:51.812Z INFO  - docker run -d -p 1764:8000 --name test_0_c348bc62 -e WEBSITE_SITE_NAME=sockettest -e WEBSITE_AUTH_ENABLED=False -e WEBSITE_ROLE_INSTANCE_ID=0 -e WEBSITE_HOSTNAME=sockettest.chinacloudsites.cn -e WEBSITE_INSTANCE_ID=08307498aa991c84523184617d17f074bad5139bd2c0710fdf2b1a0ad3d3a9b7 -e HTTP_LOGGING_ENABLED=1 appsvc/python:3.8_20210709.2 python socket_server.py 
2021-10-28T02:39:55.922Z INFO  - Initiating warmup request to container test_0_c348bc62 for site sockettest
2021-10-28T02:40:11.177Z INFO  - Waiting for response to warmup request for container test_0_c348bc62. Elapsed time = 15.2556084 sec
...
2021-10-28T02:43:33.439Z INFO  - Waiting for response to warmup request for container test_0_c348bc62. Elapsed time = 217.5175373 sec
2021-10-28T02:43:46.644Z ERROR - Container test_0_c348bc62 for site sockettest did not start within expected time limit. Elapsed time = 230.7221775 sec
2021-10-28T02:43:46.645Z ERROR - Container test_0_c348bc62 didn't respond to HTTP pings on port: 8000, failing site start. See container logs for debugging.
2021-10-28T02:43:46.672Z INFO  - Stopping site sockettest because it failed during startup.

PS:应用上云的需求。

 

问题解决

这是因为App Service Linux使用Container的启动需要Python代码中对HTTP进行正确的响应,否则Site无法启动。而这次的Python代码并不包含对HTTP请求的响应(需要Web框架),所以无法正确启动。

在Azure App Service for Linux - Python的文档中,主要介绍的两种Web框架为 Flask 和 Django。 接下来,就通过Flask 和SocketIO来实现WebSocket功能。

 

实现 Python SocketIO 代码及步骤

1)创建 app.py 文件,并复制以下内容,作为Socket的服务端及Flask应用的启动

from flask import Flask, render_template, session, copy_current_request_context
from flask_socketio import SocketIO, emit, disconnect
from threading import Lock
import os
async_mode = None
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app, async_mode=async_mode)
thread = None
thread_lock = Lock()
## Used by App Service For linux
PORT = os.environ["PORT"] 
serverIP = "0.0.0.0"
# # Used by Local debug.
# PORT = 5000 
# serverIP = "127.0.0.1"
@app.route('/')
def index():
    return render_template('index.html', async_mode=socketio.async_mode)
@socketio.on('my_event', namespace='/test')
def test_message(message):
    print('receive message:' + message['data'],)
    session['receive_count'] = session.get('receive_count', 0) + 1
    emit('my_response',
         {'data': message['data'], 'count': session['receive_count']})
@socketio.on('my_broadcast_event', namespace='/test')
def test_broadcast_message(message):
    print('broadcast message:' + message['data'],)
    session['receive_count'] = session.get('receive_count', 0) + 1
    emit('my_response',
         {'data': message['data'], 'count': session['receive_count']},
         broadcast=True)
@socketio.on('disconnect_request', namespace='/test')
def disconnect_request():
    @copy_current_request_context
    def can_disconnect():
        disconnect()
    session['receive_count'] = session.get('receive_count', 0) + 1
    emit('my_response',
         {'data': 'Disconnected!', 'count': session['receive_count']},
         callback=can_disconnect)
if __name__ == '__main__':
    socketio.run(app,port=PORT, host=serverIP, debug=True)
    print('socket io start')

 

2)创建 template/index.html,并复制以下内容,作为Socket的客户端,验证WebSocket的正常工作

<!DOCTYPE HTML>
<html>
<head>
    <title>Socket-Test</title>
    <script src="//code.jquery.com/jquery-1.12.4.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
    <script type="text/javascript" charset="utf-8">
        $(document).ready(function() {
            namespace = '/test';
            var socket = io(namespace);
            socket.on('connect', function() {
                socket.emit('my_event', {data: 'connected to the SocketServer...'});
            });
            socket.on('my_response', function(msg, cb) {
                $('#log').append('<br>' + $('<div/>').text('logs #' + msg.count + ': ' + msg.data).html());
                if (cb)
                    cb();
            });
            $('form#emit').submit(function(event) {
                socket.emit('my_event', {data: $('#emit_data').val()});
                return false;
            });
            $('form#broadcast').submit(function(event) {
                socket.emit('my_broadcast_event', {data: $('#broadcast_data').val()});
                return false;
            });
            $('form#disconnect').submit(function(event) {
                socket.emit('disconnect_request');
                return false;
            });
        });
    </script>
</head>
<body style="background-color:white;">
    <h1 style="background-color:white;">Socket</h1>
    <form id="emit" method="POST" action='#'>
        <input type="text" name="emit_data" id="emit_data" placeholder="Message">
        <input type="submit" value="Send Message">
    </form>
    <form id="broadcast" method="POST" action='#'>
        <input type="text" name="broadcast_data" id="broadcast_data" placeholder="Message">
        <input type="submit" value="Send Broadcast Message">
    </form>
    <form id="disconnect" method="POST" action="#">
        <input type="submit" value="Disconnect Server">
    </form>
    <h2 style="background-color:white;">Logs</h2>
    <div id="log" ></div>
</body>
</html>

 

3)创建 requirements.txt 文件,并包含以下module及版本,如果版本不适合,可以适当修改。

Flask==1.0.2
Flask-Login==0.4.1
Flask-Session==0.3.1
itsdangerous==1.1.0
Jinja2==2.10
MarkupSafe==1.1.0
six==1.11.0
Werkzeug==0.14.1
Flask-SocketIO==4.3.1
python-engineio==3.13.2
python-socketio==4.6.0
eventlet==0.30.2

以上三个就是整个项目的源文件,VS Code中的文件结构为:

 

 

4)在VS Code中使用az webapp up来部署Python Web应用

#设置登录环境为中国区Azure
az cloud set -n AzureChinaCloud
az login
#部署代码,如果pythonlinuxwebsocket01不存在,则自动创建定价层位B1的App Service
az webapp up --sku B1 --name pythonlinuxwebsocket01

效果展示:

 

5)修改App Service的启动命令

gunicorn --worker-class eventlet -w 1 app:app

注:为了避免 flask-socketIO 服务器部署 400 Bad Request 问题,所以需要使用 eventlet 作为工作进程。详细说明可见:https://blog.csdn.net/weixin_43958804/article/details/109024348

 

6)  开启WebSocket, 启用HTTP,  设置PORT参数

注:修改后,重启App Service。如果重启后使用HTTP请求,但是发生了302跳转到HTTPS的情况,就可以考虑重新部署一次站点。使用第四步方法,az webapp up然container重新生成项目信息。

7)验证Web Socket

使用HTTP访问刚刚部署的App Service URL。

 

 

 

附录一:解决flask-socketIO 服务器部署 400 Bad Request 问题

使用eventlet,设置启动命令:gunicorn --worker-class eventlet -w 1 app:app

 

附录二:Gunicorn ImportError: cannot import name 'ALREADY_HANDLED' from 'eventlet.wsgi' in docker

Installing older version of eventlet solved the problem: pip install eventlet==0.30.2

 

参考资料:

Implement a WebSocket Using Flask and Socket-IO(Python): https://medium.com/swlh/implement-a-websocket-using-flask-and-socket-io-python-76afa5bbeae1

解决flask-socketIO 服务器部署 400 Bad Request 问题:https://blog.csdn.net/weixin_43958804/article/details/109024348

相关文章
|
1月前
|
数据采集 存储 Web App开发
逆向音乐APP:Python爬虫获取音乐榜单
逆向音乐APP:Python爬虫获取音乐榜单
196 58
|
1月前
|
SQL 安全 算法
解读 Python 3.14:模板字符串、惰性类型、Zstd压缩等7大核心功能升级
Python 3.14 引入了七大核心技术特性,大幅提升开发效率与应用安全性。其中包括:t-strings(PEP 750)提供更安全灵活的字符串处理;类型注解惰性求值(PEP 649)优化启动性能;外部调试器API标准化(PEP 768)增强调试体验;原生支持Zstandard压缩算法(PEP 784)提高效率;REPL交互环境升级更友好;UUID模块扩展支持新标准并优化性能;finally块语义强化(PEP 765)确保资源清理可靠性。这些改进使Python在后端开发、数据科学等领域更具竞争力。
62 5
解读 Python 3.14:模板字符串、惰性类型、Zstd压缩等7大核心功能升级
|
1月前
|
测试技术 Linux 网络安全
【App Services】App Service报错远程证书无效 - "The remote certificate is invalid according to the validation procedure"
在开发环境中,新部署的应用(App Service)无法与 Salesforce 的远程端点建立 SSL/TLS 连接,报错显示证书无效。经分析,防火墙启用了 SSL Inspection,插入了私有 CA 签发的中间证书,导致 App Service 无法验证。解决方案包括禁用 SSL Inspection、设置 `WEBSITE_LOAD_ROOT_CERTIFICATES` 环境变量或临时禁用代码中的 SSL 验证(仅限测试环境)。
|
2月前
|
存储 监控 API
【Azure App Service】分享使用Python Code获取App Service的服务器日志记录管理配置信息
本文介绍了如何通过Python代码获取App Service中“Web服务器日志记录”的配置状态。借助`azure-mgmt-web` SDK,可通过初始化`WebSiteManagementClient`对象、调用`get_configuration`方法来查看`http_logging_enabled`的值,从而判断日志记录是否启用及存储方式(关闭、存储或文件系统)。示例代码详细展示了实现步骤,并附有执行结果与官方文档参考链接,帮助开发者快速定位和解决问题。
116 24
|
3月前
|
网络协议
【Azure App Service】App Service 如何配置私网域名以及证书呢?
本文解答了关于 Azure App Service 如何配置私网域名及证书的问题。App Service 不支持私网域名,自定义域名需配置在公共 DNS 服务器上。文章引用官方文档详细说明了映射自定义 DNS 的步骤,并附带参考资料链接,帮助用户深入了解相关配置方法。
|
2月前
|
人工智能 JSON 小程序
【一步步开发AI运动APP】七、自定义姿态动作识别检测——之规则配置检测
本文介绍了如何通过【一步步开发AI运动APP】系列博文,利用自定义姿态识别检测技术开发高性能的AI运动应用。核心内容包括:1) 自定义姿态识别检测,满足人像入镜、动作开始/停止等需求;2) Pose-Calc引擎详解,支持角度匹配、逻辑运算等多种人体分析规则;3) 姿态检测规则编写与执行方法;4) 完整示例展示左右手平举姿态检测。通过这些技术,开发者可轻松实现定制化运动分析功能。
|
24天前
|
存储 消息中间件 前端开发
PHP后端与uni-app前端协同的校园圈子系统:校园社交场景的跨端开发实践
校园圈子系统校园论坛小程序采用uni-app前端框架,支持多端运行,结合PHP后端(如ThinkPHP/Laravel),实现用户认证、社交关系管理、动态发布与实时聊天功能。前端通过组件化开发和uni.request与后端交互,后端提供RESTful API处理业务逻辑并存储数据于MySQL。同时引入Redis缓存热点数据,RabbitMQ处理异步任务,优化系统性能。核心功能包括JWT身份验证、好友系统、WebSocket实时聊天及活动管理,确保高效稳定的用户体验。
99 3
PHP后端与uni-app前端协同的校园圈子系统:校园社交场景的跨端开发实践
|
1月前
|
人工智能 JavaScript 前端开发
借助 CodeBuddy,我轻松开发出三分钟读书 App
借助 CodeBuddy,我轻松开发出三分钟读书 App
46 6
|
1月前
|
人工智能 小程序 API
【一步步开发AI运动APP】九、自定义姿态动作识别检测——之关键点追踪
本文介绍了【一步步开发AI运动APP】系列中的关键点追踪技术。此前分享的系列博文助力开发者打造了多种AI健身场景的小程序,而新系列将聚焦性能更优的AI运动APP开发。文章重点讲解了“关键点位变化追踪”能力,适用于动态运动(如跳跃)分析,弥补了静态姿态检测的不足。通过`pose-calc`插件,开发者可设置关键点(如鼻子)、追踪方向(X或Y轴)及变化幅度。示例代码展示了如何在`uni-app`框架中使用`createPointTracker`实现关键点追踪,并结合人体识别结果完成动态分析。具体实现可参考文档与Demo示例。
|
3月前
|
安全 API Swift
如何在苹果内购开发中获取App Store Connect API密钥-共享密钥理解内购安全-优雅草卓伊凡
如何在苹果内购开发中获取App Store Connect API密钥-共享密钥理解内购安全-优雅草卓伊凡
184 15
如何在苹果内购开发中获取App Store Connect API密钥-共享密钥理解内购安全-优雅草卓伊凡

热门文章

最新文章

推荐镜像

更多