Unity WebGL下用纯JavaScript调用Google Cloud Speech-to-Text API遇400错误求助
解决方案:Unity WebGL + 纯JS调用Google Cloud Speech-to-Text API
核心错误原因
400 Bad Request基本都来自以下几个硬伤,先逐一核对:
- 音频格式不匹配:API要求必须是16kHz采样率、单声道、16位PCM(LINEAR16编码),格式不对直接拒绝
- API Key使用错误:API Key应放在URL参数
key=xxx或请求头X-Goog-Api-Key: xxx,而非Authorization: Bearer xxx(Bearer是OAuth令牌的用法) - 请求JSON结构错误:必须包含
config和audio两个顶级字段,缺一不可
完整实现代码(jslib + Unity C#)
1. WebGL麦克风采集与API请求的jslib
创建SpeechToText.jslib,放入Unity项目的Plugins/WebGL目录:
mergeInto(LibraryManager.library, { // 初始化麦克风,强制匹配API要求的音频格式 InitMicrophone: function() { navigator.mediaDevices.getUserMedia({ audio: { sampleRate: 16000, channelCount: 1, sampleSize: 16, echoCancellation: true } }) .then(stream => { const audioContext = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: 16000 }); const source = audioContext.createMediaStreamSource(stream); const processor = audioContext.createScriptProcessor(4096, 1, 1); source.connect(processor); processor.connect(audioContext.destination); processor.onaudioprocess = function(e) { const inputBuffer = e.inputBuffer; const channelData = inputBuffer.getChannelData(0); // 把浏览器返回的32位浮点音频转成API要求的16位PCM const pcmData = new Int16Array(channelData.length); for (let i = 0; i < channelData.length; i++) { const normalized = Math.max(-1, Math.min(1, channelData[i])); pcmData[i] = normalized < 0 ? normalized * 0x8000 : normalized * 0x7FFF; } // 转成base64编码 const base64 = btoa(String.fromCharCode(...new Uint8Array(pcmData.buffer))); // 发送识别请求 _SendSpeechRequest(base64); }; }) .catch(err => console.error("麦克风初始化失败:", err)); }, // 发送POST请求到Speech-to-Text API SendSpeechRequest: function(audioBase64Ptr) { const audioBase64 = UTF8ToString(audioBase64Ptr); const apiKey = "YOUR_API_KEY"; // 替换成你的API Key const url = `https://speech.googleapis.com/v1/speech:recognize?key=${apiKey}`; const payload = JSON.stringify({ config: { encoding: "LINEAR16", sampleRateHertz: 16000, languageCode: "zh-CN", // 替换成目标语言,比如en-US enableAutomaticPunctuation: true }, audio: { content: audioBase64 } }); fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: payload }) .then(response => { if (!response.ok) throw new Error(`HTTP错误码: ${response.status}`); return response.json(); }) .then(data => { // 提取识别结果,传回Unity const transcript = data.results[0]?.alternatives[0]?.transcript || "无识别结果"; const transcriptPtr = allocateUTF8(transcript); _OnSpeechRecognitionResult(transcriptPtr); free(transcriptPtr); }) .catch(err => console.error("API请求失败:", err)); } }); // 辅助函数:将字符串转为Unity可读取的UTF8指针 function allocateUTF8(str) { const buffer = new TextEncoder().encode(str + "\0"); const ptr = _malloc(buffer.length); writeArrayToMemory(buffer, ptr); return ptr; }
2. Unity C#调用脚本
创建C#脚本挂载到任意GameObject:
using UnityEngine; using System.Runtime.InteropServices; public class SpeechRecognitionManager : MonoBehaviour { [DllImport("__Internal")] private static extern void InitMicrophone(); [DllImport("__Internal")] private static extern void SendSpeechRequest(string audioBase64); // 接收jslib传回的识别结果 [MonoPInvokeCallback(typeof(System.Action<string>))] private static void OnSpeechRecognitionResult(string result) { Debug.Log("识别结果: " + result); // 这里添加结果处理逻辑,比如显示到UI } void Start() { #if UNITY_WEBGL && !UNITY_EDITOR InitMicrophone(); #endif } }
关键注意事项
- API权限检查:确保Google Cloud控制台中已启用
Cloud Speech-to-Text API,且API Key未被限制IP或调用次数 - CORS配置:如果部署到自有服务器,需确保服务器允许跨域请求
speech.googleapis.com;Unity编辑器中可在Player Settings > WebGL > Publishing Settings开启Enable CORS - 音频长度限制:单次POST请求最多处理1分钟音频,如需更长音频需改用流式识别(WebSocket协议)
错误排查步骤
- 打开浏览器开发者工具(F12),查看Network标签:
- 核对Request URL是否包含正确的API Key
- 检查Request Payload的JSON结构是否与示例一致
- 查看Response的详细错误信息(Google API会返回具体原因,比如
invalid encoding或API key not valid)
- 用Postman单独测试API Key:发送一个符合格式的测试请求,确认Key本身有效
内容的提问来源于stack exchange,提问作者Niv.R.
相关产品推荐
相关产品推荐

