嵌入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
相关产品推荐
相关产品推荐

