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

无法在Apache Superset中嵌入Dash WSGI应用iframe问题求助

问题描述

前同事开发了基于Apache Superset与Dash WSGI的内部数据可视化工具,现在尝试在Superset中通过HTML iframe嵌入该Dash应用时无内容显示,但本地创建简单HTML文件调用iframe却能正常工作。两者均部署在NGINX后实现HTTPS转发,相关配置如下:

Apache Superset 配置

superset_config.py(不含密钥、SQL URI及服务器信息)

DISPLAY_MAX_ROW = 1000
ROW_LIMIT = 1000000
SQL_MAX_ROW = 1000000

# Flask-WTF flag for CSRF
WTF_CSRF_ENABLED = False
# Add endpoints that need to be exempt from CSRF protection
WTF_CSRF_EXEMPT_LIST = []
# A CSRF token that expires in 1 year
WTF_CSRF_TIME_LIMIT = 60 * 60 * 24 * 365

# Set this API key to enable Mapbox visualizations
MAPBOX_API_KEY = ''

FEATURE_FLAGS = {
    "ALERT_REPORTS": True,
    "DASHBOARD_CROSS_FILTERS": True,
    "DASHBOARD_FILTERS_EXPERIMENTAL": True,
    "DASHBOARD_NATIVE_FILTERS_SET": True,
    "DASHBOARD_NATIVE_FILTERS": True,
    "DASHBOARD_RBAC": True,
    "DYNAMIC_PLUGINS": True,
    "ENABLE_TEMPLATE_PROCESSING": True
}

ENABLE_CORS = True
CORS_OPTIONS = {
    'allow_headers': ['*'],
    'origins': ['*'],
    'resources': ['*']
}

EXPLORE_FORM_DATA_CACHE_CONFIG = {
    'CACHE_TYPE': 'RedisCache',
    'CACHE_DEFAULT_TIMEOUT': 86400,
    'CACHE_KEY_PREFIX': 'EXPLORE_FORM_DATA_CACHE_CONFIG',
    'CACHE_REDIS_URL': 'redis://localhost:6379/0'
}

FILTER_STATE_CACHE_CONFIG = {
    'CACHE_TYPE': 'RedisCache',
    'CACHE_DEFAULT_TIMEOUT': 86400,
    'CACHE_KEY_PREFIX': 'FILTER_STATE_CACHE_CONFIG',
    'CACHE_REDIS_URL': 'redis://localhost:6379/0'
}

TALISMAN_ENABLED = True
TALISMAN_CONFIG = {
    "content_security_policy": {
        "img-src": [
            "'self'",
            "data:"
        ],
        "connect-src": [
            "'self'",
            "https://api.mapbox.com",
            "https://events.mapbox.com",
        ],
        "style-src": [
            "'self'",
            "'unsafe-inline'"
        ],
        "frame-ancestors": [
            "'self'"
        ]
    },
    "content_security_policy_nonce_in": [
        "script-src"
    ],
    "force_https": True
}

Superset的NGINX配置(隐藏证书及服务器信息)

server {
        listen 443 ssl;
        listen [::]:443 ssl;

        location / {
                proxy_set_header Host $http_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;

                proxy_redirect off;
        }
}

Dash WSGI 配置

代码

from dash import Dash, dcc, html, Input, Output, callback
import apps
import os
import pkgutil
import re

superset_colors = {"blue" : "rgb(32,167,201)"}

app = Dash(__name__, suppress_callback_exceptions=True, title = "IMEDA")

server = app.server

app.layout = html.Div([
    dcc.Location(id='url', refresh=False),
    html.Div(id='page-content')
])

@callback(Output('page-content', 'children'), Input('url', 'pathname'))

def display_page(pathname):
    address = re.search(r"/apps/(.*)", pathname)
    modules = [a.name  for a in pkgutil.iter_modules(apps.__path__)]

    if address is not None:
        dashboard = address.group(1)

    if address is None or dashboard not in modules:
        return '404'
    else:
        return getattr(apps, dashboard).layout

if __name__ == '__main__':
    app.run(debug=True)

Dash WSGI的NGINX配置

server {
        listen 8443 ssl;
        listen [::]:8443 ssl;

        location / {
                proxy_set_header Host $http_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;

                proxy_redirect off;
        }
}

已尝试的解决步骤

  • 调整superset_config.py和app.py中的CSP设置
  • 调整Superset和Dash的NGINX HTTP头配置
  • 本地创建HTML文件调用iframe,能正常工作

解决方案

问题核心在于Superset的CSP(内容安全策略)限制了iframe的嵌入来源,同时Dash应用未配置允许被Superset域名嵌入的响应头,以下是具体修复步骤:

1. 修改Superset的TALISMAN CSP配置

在superset_config.py的TALISMAN_CONFIG中,新增frame-src并添加Dash应用的完整HTTPS地址,同时更新connect-src允许Dash的API请求:

"content_security_policy": {
    "img-src": [
        "'self'",
        "data:"
    ],
    "connect-src": [
        "'self'",
        "https://api.mapbox.com",
        "https://events.mapbox.com",
        "https://your-dash-domain:8443"  # 替换为你的Dash应用域名+端口
    ],
    "style-src": [
        "'self'",
        "'unsafe-inline'"
    ],
    "frame-src": [
        "'self'",
        "https://your-dash-domain:8443"  # 允许加载Dash的iframe内容
    ],
    "frame-ancestors": [
        "'self'"
    ]
},

2. 配置Dash应用的嵌入允许头

在Dash代码中添加响应头,允许Superset域名嵌入:

from flask import Flask

# 创建Dash app之后添加
server = app.server

@server.after_request
def add_embedding_headers(response):
    # 替换为你的Superset域名,如https://your-superset-domain
    response.headers['Content-Security-Policy'] = 'frame-ancestors https://your-superset-domain'
    return response

3. 加固NGINX配置(可选)

在Dash的NGINX配置中显式设置允许嵌入的头,避免被默认配置覆盖:

location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # 确保允许Superset嵌入
        proxy_hide_header X-Frame-Options;
        add_header Content-Security-Policy "frame-ancestors https://your-superset-domain";

        proxy_redirect off;
}

4. 重启服务

修改配置后,依次重启Superset、Dash应用及NGINX,确保配置生效。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 03:30:02