Node后端初始化Google Maps API保护密钥时遇错误求解决方案
我按照Google Maps API的JavaScript教程搭建了Web应用,为保护API密钥,尝试将初始化逻辑迁移至Node服务器,把返回的脚本字符串传递到前端并用eval()执行。但执行后Google Maps API提示缺少已传入的参数(如API密钥、回调函数);若在Node端运行该脚本,还会出现ReferenceError: window is not defined错误。请问我的实现方式是否错误?是否需要完全基于Node.js重构?
Node服务器端代码
async function startmaps(){ var payload = { key: process.env.GOOGLE_MAPS_API_KEY, libraries: ['places', 'geometry'], callback: 'initMap' }; var data = new FormData(); data.append("json", JSON.stringify(payload)); var result = fetch('https://maps.googleapis.com/maps/api/js', { method: "POST", body: data } ) .then((res) => res.text()) .then((dat) => { return { data: dat, error: false, errMsg: '' }; }) .catch((err) => { return { data: '', error: true, errMsg: err.toString() }; }); return result; }
前端调用代码
async function StartMaps(){ var result = await fetch('http://localhost:3000/mapinit') .then((res) => res.json()) .then((data) => { return data; }) .catch((error) => { return error; }); if(result.data === "undefined" || result.error){ console.log("got error"); }else{ eval(result.data); } }
执行报错信息
VM403:208 不支持无回调加载Google Maps JavaScript API
....
util.js:63 Google Maps JavaScript API警告:未提供API密钥
你的实现方式确实存在错误,不需要完全重构Node.js,问题出在这几个核心点:
Google Maps JS API不支持POST请求加载
Google Maps JavaScript API仅接受GET请求传递参数,你用POST方式提交的key、callback等参数,API根本无法识别,这就是为什么会提示缺少参数的直接原因。Node环境不存在浏览器全局对象
Google Maps JS API是为浏览器环境设计的,依赖window等浏览器专属全局变量,在Node服务器端直接运行该脚本必然会报window is not defined错误。用eval执行API脚本的方式不合理
即使拿到正确的脚本内容,eval执行会带来安全风险,而且API脚本的设计逻辑是直接插入页面运行,通过eval执行会破坏其原本的加载流程。
正确的实现思路:
Node端仅生成带参数的API加载URL
不需要请求API脚本内容,而是在Node服务器端拼接好包含密钥、回调、依赖库等参数的GET请求URL返回给前端:async function getMapApiUrl() { const params = new URLSearchParams({ key: process.env.GOOGLE_MAPS_API_KEY, libraries: 'places,geometry', callback: 'initMap' }); return { url: `https://maps.googleapis.com/maps/api/js?${params.toString()}`, error: false }; }前端通过动态创建script标签加载API
拿到Node返回的URL后,前端动态生成<script>标签插入页面,替代eval执行:async function StartMaps() { const result = await fetch('http://localhost:3000/mapinit').then(res => res.json()); if (result.error) { console.log("加载地图API失败"); return; } const script = document.createElement('script'); script.src = result.url; script.async = true; document.body.appendChild(script); }额外的密钥保护方案
可以在Google Cloud控制台设置API密钥限制,比如仅允许你的域名调用该密钥,即使密钥被公开,其他域名也无法使用。
内容的提问来源于stack exchange,提问作者devimon

