You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

浏览器可访问的Google Places API在JS中报TypeError: Failed to fetch

解决Google Places API前端fetch请求TypeError: Failed to fetch问题

问题核心

你遇到的本质是CORS跨域问题:浏览器地址栏直接访问API URL能返回结果,是因为这类请求不属于AJAX跨域请求范畴,不受CORS限制;但前端脚本通过fetch/axios发起的跨域请求,会被浏览器拦截——即使网络请求返回200状态码,浏览器也会因响应头缺少允许当前域名的Access-Control-Allow-Origin字段,拒绝将响应内容交给脚本,最终抛出TypeError: Failed to fetch,同时在DevTools中标记响应为红色。

解决方案

方案1:使用Google Places JavaScript SDK(推荐,更安全)

你已经在HTML中引入了Google Places SDK,但未利用它的内置服务处理跨域逻辑。SDK会自动规避CORS问题,且无需在请求URL中暴露API密钥:

修改HTML的Google Maps脚本

添加callback参数,指定SDK加载完成后执行的初始化函数:

<script src="https://maps.googleapis.com/maps/api/js?key=ENTER_KEY_HERE&libraries=places&callback=initMap"></script>

替换JavaScript代码为SDK调用逻辑

// 初始化函数,由Google SDK加载完成后自动调用
function initMap() {
  // 创建PlacesService实例(临时DOM元素即可满足初始化要求)
  const placesService = new google.maps.places.PlacesService(document.createElement('div'));
  
  // 请求参数
  const request = {
    placeId: 'ChIJZ92Qj31CXIYR1i6OU-1uHp0',
    fields: ['reviews'] // 指定仅获取评论字段
  };

  // 调用getDetails接口获取数据
  placesService.getDetails(request, (placeResult, status) => {
    if (status === google.maps.places.PlacesServiceStatus.OK) {
      console.log('获取到的评论:', placeResult.reviews);
    } else {
      console.error('获取数据失败:', status);
    }
  });
}

// 将初始化函数挂载到window,供SDK回调
window.initMap = initMap;

方案2:搭建后端代理(适合自定义业务逻辑场景)

通过自有后端服务转发请求,既规避CORS问题,又能保护API密钥(前端直接暴露密钥极易被滥用,导致账户产生高额不必要费用):

示例Node.js/Express后端代码

const express = require('express');
const axios = require('axios');
const app = express();
const PORT = 3001;

// 配置CORS,允许你的前端域名跨域请求
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', 'http://localhost:8080'); // 替换为你的前端实际域名
  res.header('Access-Control-Allow-Methods', 'GET');
  next();
});

// 代理接口,处理前端的评论请求
app.get('/api/get-place-reviews', async (req, res) => {
  const { placeId } = req.query;
  const googleApiKey = 'YOUR_GOOGLE_API_KEY'; // 密钥存储在后端,不暴露给前端

  try {
    const response = await axios.get('https://maps.googleapis.com/maps/api/place/details/json', {
      params: {
        key: googleApiKey,
        placeid: placeId,
        fields: 'reviews'
      }
    });
    res.json(response.data);
  } catch (error) {
    res.status(error.response?.status || 500).json({ error: error.message });
  }
});

// 启动后端服务
app.listen(PORT, () => {
  console.log(`代理服务运行在 http://localhost:${PORT}`);
});

前端修改fetch请求地址

async function getdata() {
  try {
    // 请求自有后端的代理接口
    const response = await fetch('http://localhost:3001/api/get-place-reviews?placeId=ChIJZ92Qj31CXIYR1i6OU-1uHp0');
    if (!response.ok) {
      throw new Error('请求失败');
    }
    const items = await response.json();
    console.log(items);
  } catch (err) {
    console.error(err);
  }
}
getdata();

关键提醒

生产环境中绝对不要在前端代码直接暴露Google API密钥,一旦被恶意获取,可能导致大量违规请求产生高额费用。上述两种方案均规避了密钥暴露风险,是合规的实现方式。

内容的提问来源于stack exchange,提问作者Lacnoskillz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 00:45:22