如何在JavaScript中调用GCP私有WebSocket时传递Bearer认证头
问题根源
浏览器原生WebSocket API 不支持自定义Authorization这类非标准请求头,这是浏览器的安全限制。你尝试的1.3写法里的headers参数并非标准API的一部分,仅在Node.js等非浏览器环境的WebSocket库(如ws)中有效,所以浏览器里完全不生效。而Postman能成功,是因为它不受浏览器的同源策略和头字段限制。
可行解决方案
方案1:通过查询参数传递Token(需服务端配合)
如果你的Cloud Run服务端支持从URL查询参数中解析Token,可以直接把Token拼在URL后面:
const websocketUrl = 'wss://web-adaptor-service-lz7ymxgtha-ue.a.run.app'; const gcp_auth_token = 'eyJhbGciOiJSU**************************'; // 用access_token参数传递,需服务端验证该参数 const socket = new WebSocket(`${websocketUrl}?access_token=${gcp_auth_token}`);
注意:这种方式Token会暴露在URL中(可能出现在日志、历史记录里),如果对安全性要求极高,不推荐。
方案2:用Fetch提前完成握手(现代浏览器支持)
利用fetch自定义请求头完成WebSocket握手,再通过WebSocket.from()方法接管已建立的连接(Chrome 106+、Firefox 118+支持):
const websocketUrl = 'wss://web-adaptor-service-lz7ymxgtha-ue.a.run.app'; const gcp_auth_token = 'eyJhbGciOiJSU**************************'; async function connectWs() { try { // 发送WebSocket握手请求,自定义Authorization头 const handshakeRes = await fetch(websocketUrl.replace('wss://', 'https://'), { method: 'GET', headers: { 'Authorization': `Bearer ${gcp_auth_token}`, 'Upgrade': 'websocket', 'Connection': 'Upgrade', 'Sec-WebSocket-Key': btoa(Math.random().toString()).slice(0, 16), 'Sec-WebSocket-Version': '13' } }); // 基于握手响应创建WebSocket连接 const socket = WebSocket.from(handshakeRes); // 绑定事件监听 socket.onopen = () => console.log('WebSocket连接成功'); socket.onmessage = (e) => console.log('收到消息:', e.data); socket.onerror = (err) => console.error('连接错误:', err); socket.onclose = () => console.log('连接关闭'); return socket; } catch (err) { console.error('握手失败:', err); } } // 调用连接函数 connectWs();
方案3:搭建Node.js代理服务器(兼容所有浏览器)
如果需要兼容旧浏览器,可在自己的服务器上做一层代理,前端连接代理,代理请求Cloud Run时自动添加Authorization头:
// 代理服务器代码(Node.js) const express = require('express'); const http = require('http'); const { WebSocketServer } = require('ws'); const httpProxy = require('http-proxy'); const app = express(); const server = http.createServer(app); const proxy = httpProxy.createProxyServer(); const CLOUD_RUN_WS_URL = 'wss://web-adaptor-service-lz7ymxgtha-ue.a.run.app'; const GCP_AUTH_TOKEN = 'eyJhbGciOiJSU**************************'; // 处理WebSocket升级请求 server.on('upgrade', (req, socket, head) => { // 给代理请求添加Authorization头 req.headers.authorization = `Bearer ${GCP_AUTH_TOKEN}`; proxy.ws(req, socket, head, { target: CLOUD_RUN_WS_URL, changeOrigin: true }); }); // 启动代理服务器 const PORT = 3000; server.listen(PORT, () => { console.log(`代理服务器运行在 http://localhost:${PORT}`); });
前端直接连接代理服务器即可:
const socket = new WebSocket('ws://localhost:3000');
内容的提问来源于stack exchange,提问作者Ankita
相关产品推荐
相关产品推荐

