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

嵌入Metabase图表到Vue.js时出现instanceof相关错误求助

问题:Vue项目嵌入Metabase图表时出现TypeError错误

错误信息

TypeError: Object prototype may only be an Object or null: undefined
at Function.create ()
at Object.inherits (inherits_browser.js:6:31)
at eval (data-stream.js:39:1)
at ./node_modules/jws/lib/data-stream.js (chunk-vendors.js:2033:1)
at webpack_require (app.js:279:33)
at fn (app.js:525:21)
at eval (sign-stream.js:3:1)
at ./node_modules/jws/lib/sign-stream.js (chunk-vendors.js:2043:1)
at webpack_require (app.js:279:33)
at fn (app.js:525:21)

RewardCharts.vue代码

<template>
    <h1>Reward Points Charts</h1>
    <iframe
    src="{{url}}"
    frameborder="0"
    width="800"
    height="600"
    allowtransparency
    ></iframe>
</template>
<script>
    export default {
        data() {
          return {
            url: ''
          }
        },
        created() {
            try {
                var jwt = require('jsonwebtoken');
                var METABASE_SITE_URL = "http://localhost:3000";
                var METABASE_SECRET_KEY = "#secret key from Metabase ";
                var payload = {
                  resource: { question: 2 },
                  exp: Math.round(Date.now() / 1000) + (10 * 60) // 10 minute expiration
                };
              const token = jwt.sign(payload, METABASE_SECRET_KEY);
              this.url = METABASE_SITE_URL + "/embed/question/" + token +  "#bordered=true&titled=true";
            } catch (e) {
              console.log(e)
            }
       }
};
</script>

Package.json内容

{
  "name": "nse-driver-points-collection",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build  --port 810",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "@popperjs/core": "^2.11.8",
    "axios": "^1.4.0",
    "bootstrap": "^5.3.0",
    "bootstrap-icons": "^1.10.5",
    "core-js": "^3.8.3",
    "crypto-browserify": "^3.12.0",
    "epic-spinners": "^2.0.0",
    "jsonwebtoken": "^9.0.2",
    "stream-browserify": "^3.0.0",
    "util": "^0.12.5",
    "vue": "^3.2.13",
    "vue-axios": "^3.5.2",
    "vue-router": "^4.2.5"
  },
  "devDependencies": {
    "@babel/core": "^7.12.16",
    "@babel/eslint-parser": "^7.12.16",
    "@types/jsonwebtoken": "^9.0.4",
    "@vue/cli-plugin-babel": "~5.0.0",
    "@vue/cli-plugin-eslint": "~5.0.0",
    "@vue/cli-service": "~5.0.0",
    "eslint": "^7.32.0",
    "eslint-plugin-vue": "^8.0.3",
    "webpack": "^5.89.0",
    "webpack-cli": "^4.9.2"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/vue3-essential",
      "eslint:recommended"
    ],
    "parserOptions": {
      "parser": "@babel/eslint-parser"
    },
    "rules": {}
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead",
    "not ie 11"
  ]
}

解决方法

你遇到的错误核心原因是:jsonwebtoken是专为Node.js环境设计的库,它依赖Node.js的核心模块(如stream、crypto),这些模块在浏览器环境中无法直接运行,强行在前端使用会导致webpack打包时出现继承相关的报错。此外你的Vue模板语法也有小问题,同时密钥格式需要修正。

1. 把JWT生成逻辑迁移到后端

不要在前端组件中直接调用jsonwebtoken,而是编写一个后端接口来生成签名后的嵌入URL。以下是Node.js + Express的示例:

// 后端server.js示例
const express = require('express');
const jwt = require('jsonwebtoken');
const cors = require('cors');
const app = express();

app.use(cors()); // 处理跨域问题
const METABASE_SITE_URL = "http://localhost:3000";
const METABASE_SECRET_KEY = "你的Metabase密钥"; // 注意去掉多余空格和注释

app.get('/api/metabase-embed-url', (req, res) => {
  const payload = {
    resource: { question: 2 },
    exp: Math.round(Date.now() / 1000) + (10 * 60) // 10分钟过期
  };
  const token = jwt.sign(payload, METABASE_SECRET_KEY);
  const embedUrl = `${METABASE_SITE_URL}/embed/question/${token}#bordered=true&titled=true`;
  res.json({ url: embedUrl });
});

app.listen(3001, () => console.log('后端服务运行在3001端口'));

2. 修改Vue组件,调用后端接口获取URL

同时修正Vue3的属性绑定语法,把src="{{url}}"改为:src="url":

<template>
  <h1>Reward Points Charts</h1>
  <iframe
    :src="url"
    frameborder="0"
    width="800"
    height="600"
    allowtransparency
  ></iframe>
</template>
<script>
import axios from 'axios';

export default {
  data() {
    return {
      url: ''
    }
  },
  async created() {
    try {
      const response = await axios.get('http://localhost:3001/api/metabase-embed-url');
      this.url = response.data.url;
    } catch (e) {
      console.error('获取嵌入URL失败:', e);
    }
  }
};
</script>

3. 额外注意事项

  • 确保你的Metabase密钥没有多余的空格或注释(你代码里的METABASE_SECRET_KEY值后面带了空格和注释,会导致签名无效)
  • 如果后端和前端端口不同,必须处理跨域问题,上面的后端示例已经用cors中间件解决,开发环境也可以在Vue的vue.config.js中配置代理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 22:35:54