Vue项目中使用@azure/web-pubsub无法生成WebPubSubClient的clientAccessUri
Vue.js集成Azure Web PubSub时的JWT KeyObject实例判断错误
我在Vue.js应用中尝试用Azure Web PubSub实现动态群组的发布订阅功能,先解决了构建阶段的crypto/stream/Buffer/child_process未定义问题——通过安装crypto-browserify、stream-browserify、buffer包,并在webpack.config.js中添加fallback配置:
fallback: { // not present by default "crypto": require.resolve("crypto-browserify"), "stream": require.resolve("stream-browserify"), "buffer": require.resolve("buffer"), //"util": false, "child_process": false, }
项目构建成功后,执行以下两类操作时均报错:"Right-hand side of 'instanceof' is not an object",错误来自jsonwebtoken/sign.js第108行:
if (secretOrPrivateKey != null && !(secretOrPrivateKey instanceof KeyObject)) { try { secretOrPrivateKey = createPrivateKey(secretOrPrivateKey) } catch (_) { try { secretOrPrivateKey = createSecretKey(typeof secretOrPrivateKey === 'string' ? Buffer.from(secretOrPrivateKey) : secretOrPrivateKey) } catch (_) { return failure(new Error('secretOrPrivateKey is not valid key material')); } } }
注:未单独安装jsonwebtoken,它是@azure/identity的依赖。
错误场景1:获取客户端访问URL创建WebPubSubClient
const key = new AzureKeyCredential(WPS_APIKEY); const serviceClient = new WebPubSubServiceClient(WPS_ENDPOINT, key, hubName); const fetchClientAccessUrl = async (_: GetClientAccessUrlOptions) => { return ( await serviceClient.getClientAccessToken({ roles: [`webpubsub.joinLeaveGroup.${groupName}`, `webpubsub.sendToGroup.${groupName}`], }) ).url; }; let client = new WebPubSubClient({ getClientAccessUrl: fetchClientAccessUrl, } as WebPubSubClientCredential); client.on("connected", (e) => { console.log(`Connection ${e.connectionId} is connected.`); }); client.on("disconnected", (e) => { console.log(`Connection disconnected: ${e.message}`); }); await client.start(); await client.joinGroup(groupName); await client.sendToGroup(groupName, { conversationId: this.$data.conversation.conversationId, conversationContext: this.$data.conversation.conversationContext, message: { messageId: 100, message: `Hello, You are welcome to the group: ${groupName}`, timestamp: "08-06 06:20 PM", sender: this.user.userName } }, "json");
错误场景2:动态创建群组并添加用户
const key = new AzureKeyCredential(WPS_APIKEY); const chatHub = new WebPubSubServiceClient(WPS_ENDPOINT, key, hubName); let groupExists = await checkGroupExists(groupName); if (!groupExists) { let group = await chatHub.group(groupName); users.forEach(async usr => { await group.addUser(usr); }); }
项目环境
- Node版本:v20.2.0
- npm版本:v9.6.3
- 依赖列表:
"dependencies": { "@azure/identity": "^3.2.2", "@azure/web-pubsub": "^1.1.1", "@azure/web-pubsub-client": "^1.0.0-beta.3", "axios": "0.21.4", "core-js": "3.25.3", "crypto-browserify": "^3.12.0", "msal": "^1.4.18", "stream-browserify": "^3.0.0", "util": "^0.12.5", "uuid": "^9.0.0", "vue": "2.6.14", "vue-i18n": "8.27.2", "vue-router": "3.5.2", "vuex": "3.6.2" }, "devDependencies": { "@babel/core": "7.15.5", "@babel/eslint-parser": "7.15.7", "@babel/preset-env": "7.15.6", "@types/jest": "27.4.0", "@types/node": "17.0.16", "@types/uuid": "^9.0.0", "@typescript-eslint/eslint-plugin": "5.11.0", "@typescript-eslint/parser": "5.11.0", "@vue/eslint-config-typescript": "9.1.0", "@vue/test-utils": "1.2.2", "@vue/vue2-jest": "27.0.0-alpha.2", "babel-loader": "8.2.2", "clean-webpack-plugin": "4.0.0", "concurrently": "7.4.0", "cors": "2.8.5", "css-loader": "6.2.0", "dotenv-webpack": "7.0.3", "eslint": "7.32.0", "eslint-plugin-vue": "8.0.1", "eslint-webpack-plugin": "3.2.0", "html-webpack-plugin": "5.3.2", "jest": "27.3.1", "jest-fetch-mock": "3.0.3", "jest-sonar-reporter": "2.0.0", "mini-css-extract-plugin": "2.5.3", "nodemon": "2.0.20", "postcss-loader": "6.1.1", "process": "0.11.10", "sass": "1.41.1", "sass-loader": "12.1.0", "serve": "12.0.1", "stylelint": "13.13.1", "stylelint-config-sass-guidelines": "8.0.0", "terser-webpack-plugin": "5.2.4", "ts-jest": "27.1.3", "ts-loader": "9.2.6", "typescript": "5.1.3", "vue-loader": "15.9.8", "vue-remove-attributes": "1.0.3", "vue-template-compiler": "2.6.14", "webpack": "5.74.0", "webpack-bundle-analyzer": "4.6.1", "webpack-cli": "4.10.0", "webpack-dev-server": "4.11.1" }
解决方案
这个错误的根源是浏览器环境中缺少Node.js原生的KeyObject类型,而jsonwebtoken在签名时需要用它做实例判断。解决步骤如下:
- 补充webpack的ProvidePlugin配置:
在webpack.config.js中添加ProvidePlugin,注入Buffer和process,同时完善fallback和alias配置:
const webpack = require('webpack'); module.exports = { // ...其他配置 plugins: [ new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'], process: 'process/browser', }), ], resolve: { fallback: { "crypto": require.resolve("crypto-browserify"), "stream": require.resolve("stream-browserify"), "buffer": require.resolve("buffer"), "util": require.resolve("util/"), "child_process": false, }, alias: { 'crypto': 'crypto-browserify', } } };
- 调整Azure SDK的使用架构:
@azure/web-pubsub的服务端SDK(WebPubSubServiceClient)不适合在浏览器环境运行,因为它需要使用密钥生成访问令牌,密钥暴露在前端会有泄露风险。正确做法:
- 在后端服务部署
WebPubSubServiceClient,提供接口供前端调用,返回生成好的客户端访问URL。 - 前端仅使用
@azure/web-pubsub-client连接该URL,完成订阅、发消息等操作。
依赖版本调整:
将@azure/web-pubsub-client升级到稳定版(当前最新稳定版为1.0.1),beta版本可能存在浏览器兼容性问题。同时移除前端不需要的@azure/identity依赖(后端使用则保留在后端项目中)。密钥安全验证:
确保前端代码中没有直接暴露Azure Web PubSub的API密钥,所有令牌生成逻辑移到后端,避免密钥泄露风险。
内容的提问来源于stack exchange,提问作者Binod Mahto
相关产品推荐
相关产品推荐

