You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Zoom Web SDK加入会议超时失败问题(Flask后端)

问题描述

尝试用Flask作为后端实现Zoom Web SDK客户端视图,初始化环节执行正常,但点击加入会议时出现如下提示:

Joining Meeting Timeout.
Fail to join the meeting

已关闭会议等候室功能,控制台显示会议号、密码、签名等各项数据均准确,请求排查并解决加入会议失败的问题。

前端代码

<html>
<body>
</body>
<script src="https://source.zoom.us/2.9.7/lib/vendor/react.min.js"></script>
<script src="https://source.zoom.us/2.9.7/lib/vendor/react-dom.min.js"></script>
<script src="https://source.zoom.us/2.9.7/lib/vendor/redux.min.js"></script>
<script src="https://source.zoom.us/2.9.7/lib/vendor/redux-thunk.min.js"></script>
<script src="https://source.zoom.us/2.9.7/lib/vendor/lodash.min.js"></script>

<!-- CDN for client view -->
<script src="https://source.zoom.us/zoom-meeting-2.9.7.min.js"></script>

<head>
  <link type="text/css" rel="stylesheet" href="https://source.zoom.us/2.9.5/css/bootstrap.css" />
  <link type="text/css" rel="stylesheet" href="https://source.zoom.us/2.9.5/css/react-select.css" />
</head>

<script>
ZoomMtg.setZoomJSLib('https://source.zoom.us/2.9.7/lib', '/av')
// loads dependent assets
ZoomMtg.preLoadWasm()
ZoomMtg.prepareWebSDK()
// loads language files, also passes any error messages to the ui
ZoomMtg.i18n.load('en-US')
ZoomMtg.i18n.reload('en-US')

const sdkKey = "xxxxxxx";
const userName = sessionStorage.getItem("N");
const meetingNumber = sessionStorage.getItem("ID");
const passWord = sessionStorage.getItem("Pass");
const leaveUrl = "http://localhost:5050/videolist";
console.log(meetingNumber)
console.log(passWord)

//const KJUR = require('jsrsasign')
// https://www.npmjs.com/package/jsrsasign

const signature = "{{ signature }}"
console.log(signature)
ZoomMtg.init({
  leaveUrl: leaveUrl, // https://example.com/thanks-for-joining
  success: (success) => {
    console.log('Success init')
    ZoomMtg.join({
      sdkKey: sdkKey,
      signature: signature, // role in SDK signature needs to be 0
      meetingNumber: meetingNumber,
      passWord: passWord,
      userName: userName,
      userEmail: "xxxxxx", //Actual Email ID was given
      success: (success) => {
        console.log('Success join')
        console.log(success)
      },
      error: (error) => {
        console.log("A" + error + " B " + error.message)
        console.log(sdkKey)
        console.log(signature)
        console.log(meetingNumber)
        console.log(passWord)
        console.log(userName)
        
      }
    })
  },
  error: (error) => {
    console.log(error)
  }
})
</script>

<!--
<script src="{{ url_for('static', filename='script/meeting.js') }}" type="module"></script>
-->
</html>

后端Flask代码

@app.route('/meeting/<IDP>', methods=['GET'])
def meet(IDP):
    ID = IDP[:IDP.index(' ')]
    payload = {'sdkKey': SDK_KEY, "meetingNumber": ID, "role": 0, "user": IDP[IDP.index(' ')+1:], "iat": time.strftime("%d %b %y %H:%M:%S",time.gmtime())}
    encoded = jwt.encode({"some": payload}, SECRET, algorithm="HS256")
    return render_template('meeting.html', signature = encoded)

问题排查与修复

1. 签名生成逻辑错误(核心问题)

Zoom Web SDK对签名JWT的格式有严格要求,当前后端代码存在两个致命错误:

  • payload被错误嵌套在some字段中,Zoom无法识别有效信息
  • iat使用了格式化的时间字符串,而非要求的Unix时间戳(整数)

这两个错误会直接导致签名验证失败,触发加入超时。

修复后的后端代码

import time
import jwt

@app.route('/meeting/<IDP>', methods=['GET'])
def meet(IDP):
    ID = IDP[:IDP.index(' ')]
    # 按照Zoom要求构造payload,iat为Unix时间戳,添加合理过期时间
    payload = {
        'sdkKey': SDK_KEY,
        'meetingNumber': ID,
        'role': 0,
        'user': IDP[IDP.index(' ')+1:],
        'iat': int(time.time()),
        'exp': int(time.time()) + 3600  # 签名1小时内有效
    }
    # 直接对payload签名,无需嵌套额外字段
    encoded = jwt.encode(payload, SECRET, algorithm="HS256")
    return render_template('meeting.html', signature=encoded)

2. 前端HTML结构错误

原代码中<head>标签放在了<body>和<script>之后,不符合HTML规范,可能导致样式加载异常或SDK初始化受影响。需调整结构,并同步CSS版本与SDK版本:

修复后的前端HTML结构开头

<html>
<head>
  <!-- 同步CSS版本为2.9.7,与SDK版本一致 -->
  <link type="text/css" rel="stylesheet" href="https://source.zoom.us/2.9.7/css/bootstrap.css" />
  <link type="text/css" rel="stylesheet" href="https://source.zoom.us/2.9.7/css/react-select.css" />
</head>
<body>

<!-- 所有脚本和页面内容放在body内 -->
<script src="https://source.zoom.us/2.9.7/lib/vendor/react.min.js"></script>
<script src="https://source.zoom.us/2.9.7/lib/vendor/react-dom.min.js"></script>
<script src="https://source.zoom.us/2.9.7/lib/vendor/redux.min.js"></script>
<script src="https://source.zoom.us/2.9.7/lib/vendor/redux-thunk.min.js"></script>
<script src="https://source.zoom.us/2.9.7/lib/vendor/lodash.min.js"></script>

<!-- CDN for client view -->
<script src="https://source.zoom.us/zoom-meeting-2.9.7.min.js"></script>

<!-- 后续脚本代码 -->
</body>
</html>

3. 额外验证点

  • 确认SECRET是Zoom开发者平台中对应SDK Key的Secret Key,切勿混淆其他密钥
  • 前端sdkKey必须与后端使用的SDK_KEY完全一致
  • 确保目标会议处于已启动状态(仅创建未启动的会议无法加入)
  • 检查浏览器控制台是否有CORS错误,若有需在Zoom开发者后台配置允许的域名

内容的提问来源于stack exchange,提问作者George

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 04:10:34