Superset仪表板在Web应用中嵌入的问题

huangapple go评论72阅读模式
英文:

Problem with Superset dashboard embedding in web app

问题

我正在遵循这个教程https://www.tetranyde.com/blog/embedding-superset,试图在React Js应用程序中嵌入Superset仪表板。

我认为我的代码没问题,但仪表板没有在前端渲染出来...
这是错误信息:Front

我也附上了我的服务器代码:server.js

import express from "express";
import fetch from "node-fetch";
import cors from "cors";

const PORT = 3001;
const app = express();
// 启用CORS
app.use(cors());
app.listen(PORT, () => {
  console.log(`服务器运行在端口 ${PORT}`);
});

async function fetchAccessToken() {
  try {
    const body = {
      username: "admin",
      password: "admin",
      provider: "db",
      refresh: true,
    };

    const response = await fetch(
      "http://localhost:8088/api/v1/security/login",
      {
        method: "POST",
        body: JSON.stringify(body),
        headers: {
          "Content-Type": "application/json",
        },
      }
    );

    const jsonResponse = await response.json();
    return jsonResponse?.access_token;
  } catch (e) {
    console.error(error);
  }
}

async function fetchGuestToken() {
  const accessToken = await fetchAccessToken();
  try {
    const body = {
      resources: [
        {
          type: "dashboard",
          id: "2962c53b-3364-4ad9-b4bd-35f0ff69e909",
        },
      ],
      rls: [],
      user: {
        username: "guest",
        first_name: "Guest",
        last_name: "User",
      },
    };
    const response = await fetch(
      "http://localhost:8088/api/v1/security/guest_token",
      {
        method: "POST",
        body: JSON.stringify(body),
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${accessToken}`,
        },
      }
    );
    const jsonResponse = await response.json();
    return jsonResponse?.token;
  } catch (error) {
    console.error(error);
  }
}

app.get("/guest-token", async (req, res) => {
  const token = await fetchGuestToken();
  res.json(token);
});

以及我的React Home组件代码:

import React from 'react';
import { useEffect } from "react";
import { embedDashboard } from "@superset-ui/embedded-sdk";

function Home() {
  const getToken = async () => {
    const response = await fetch("/guest-token");
    const token = await response.json();
    return token;
  }

  useEffect(() => {
    const embed = async () => {
      await embedDashboard({
        id: "2962c53b-3364-4ad9-b4bd-35f0ff69e909", // 由Superset嵌入UI提供
        supersetDomain: "http://localhost:8088",
        mountPoint: document.getElementById("dashboard"), // 在其中呈现iframe的HTML元素
        fetchGuestToken: () => getToken(),
        dashboardUiConfig: {
          hideTitle: true,
          hideChartControls: true,
          hideTab: true,
        },
      });
    }
    if (document.getElementById("dashboard")) {
      embed();
    }
  }, []);

  return (
    <div className="App">
      <h1>如何嵌入Superset仪表板</h1>
      <div id="dashboard" style={{ width: '100%', height: '800px' }} />
    </div>
  )
}

export default Home;

我认为问题可能出在服务器上,但我无法弄清楚。

英文:

I'm following this tutorial https://www.tetranyde.com/blog/embedding-superset trying to embed superset dashboard in react Js app.

I think my code is fine but the dashboard is not rendered in the front..
Here is the error :Front

I'm also joining my server code : server.js


import express from &quot;express&quot;
import fetch from &quot;node-fetch&quot;
import cors from &quot;cors&quot;
const PORT = 3001
const app = express()
// Enable CORS
app.use(cors())
app.listen(PORT, () =&gt; {
console.log(`Server running on port ${PORT}`)
})
async function fetchAccessToken() {
try {
const body = {
username: &quot;admin&quot;,
password: &quot;admin&quot;,
provider: &quot;db&quot;,
refresh: true,
}
const response = await fetch(
&quot;http://localhost:8088/api/v1/security/login&quot;,
{
method: &quot;POST&quot;,
body: JSON.stringify(body),
headers: {
&quot;Content-Type&quot;: &quot;application/json&quot;,
},
}
)
const jsonResponse = await response.json()
return jsonResponse?.access_token
} catch (e) {
console.error(error)
}
}
async function fetchGuestToken() {
const accessToken = await fetchAccessToken()
try {
const body = {
resources: [
{
type: &quot;dashboard&quot;,
id: &quot;2962c53b-3364-4ad9-b4bd-35f0ff69e909&quot;,
},
],
rls: [],
user: {
username: &quot;guest&quot;,
first_name: &quot;Guest&quot;,
last_name: &quot;User&quot;,
},
}
const response = await fetch(
&quot;http://localhost:8088/api/v1/security/guest_token&quot;,
{
method: &quot;POST&quot;,
body: JSON.stringify(body),
headers: {
&quot;Content-Type&quot;: &quot;application/json&quot;,
Authorization: `Bearer ${accessToken}`,
},
}
)
const jsonResponse = await response.json()
return jsonResponse?.token
} catch (error) {
console.error(error)
}
}
app.get(&quot;/guest-token&quot;, async (req, res) =&gt; {
const token = await fetchGuestToken()
res.json(token)
})

and my react Home component code :

import React from &#39;react&#39;
import { useEffect } from &quot;react&quot;
import { embedDashboard } from &quot;@superset-ui/embedded-sdk&quot;
function Home() {
const getToken = async () =&gt; {
const response = await fetch(&quot;/guest-token&quot;)
const token = await response.json()
return token
}
useEffect(() =&gt; {
const embed = async () =&gt; {
await embedDashboard({
id: &quot;2962c53b-3364-4ad9-b4bd-35f0ff69e909&quot;, // given by the Superset embedding UI
supersetDomain: &quot;http://localhost:8088&quot;,
mountPoint: document.getElementById(&quot;dashboard&quot;), // html element in which iframe render
fetchGuestToken: () =&gt; getToken(),
dashboardUiConfig: {
hideTitle: true,
hideChartControls: true,
hideTab: true,
},
})
}
if (document.getElementById(&quot;dashboard&quot;)) {
embed()
}
}, [])
return (
&lt;div className=&quot;App&quot;&gt;
&lt;h1&gt;How to Embed Superset Dashboard &lt;/h1&gt;
&lt;div id=&quot;dashboard&quot; style={{width:&#39;100%&#39;,height:&#39;800px&#39;}}/&gt;
&lt;/div&gt;
)
}
export default Home

I think that there is a problem with the server but I can't figure it out

答案1

得分: 3

拷贝错误文本以提高可读性:
> 拒绝显示 'http://localhost/8088'
在框架中,因为它将 'X-Frame-Options' 设置为 'SAMEORIGIN'

这是因为服务器的响应将 iframe 安全性设置为强制同源。从理论上讲,您应该能够编辑 superset_config.py 文件,如下所示:

OVERRIDE_HTTP_HEADERS = {&#39;X-Frame-Options&#39;: &#39;ALLOWALL&#39;}

但这对我不起作用。相反,罪魁祸首是 Superset 服务器正在使用的 Talisman 库,它默认为 iframes 设置了相同的源设置。

要解决这个问题,您要么修改默认的 Talisman 设置,要么通过配置关闭 Talisman,如下所示:

TALISMAN_ENABLED = False

> 无法执行 'postMessage' 在 'DOMWindow' 上:所提供的目标起源
('http://localhost:8088') 与接收窗口的起源
(null) 不匹配。

这是因为之前的错误,由于 iframe 未加载,iframe 起源是 null,因此会出现异常。

英文:

Pasting the error text here for readability:
> Refused to display 'http://localhost/8088'
in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'

This is happening because the response from the server is setting the iframe security to force same origin. Theoretically you should be able to edit the superset_config.py file with

OVERRIDE_HTTP_HEADERS = {&#39;X-Frame-Options&#39;: &#39;ALLOWALL&#39;}

but that wasn't working for me. Instead, the culprit is the Talisman library the Superset server is using which defaults the same origin setting for iframes.

To get around that, you have to either modify the default Talisman settings or turn off Talisman via config by

TALISMAN_ENABLED = False

> Failed to execute 'postMessage' on 'DOMWindow': The target origin provided
('http://localhost:8088') does not match the recipient window's origin
(null).

This is happening because of the error before, since the iframe doesn't load the iframe origin is null and thus the exception.

huangapple
  • 本文由 发表于 2023年7月11日 05:18:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/76657409.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定