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

React+Node.js城市景点查询:Mapbox API报错与响应精简需求

解决方案

一、修复Mapbox API 422错误

你遇到的422错误是因为Mapbox Geocoding API的types参数不接受单独的park值。Mapbox的POI类型有严格命名规则:

  • 要指定公园类景点,用poi.park
  • 要覆盖所有景点类POI(含湖泊、博物馆等),直接用poi
  • 还可以组合多个具体类型,比如poi.park,poi.lake

修正后的Node.js请求示例(以axios为例)

const axios = require('axios');

async function fetchCityAttractions(city) {
  try {
    const apiRes = await axios.get(`https://api.mapbox.com/geocoding/v5/mapbox.places/${encodeURIComponent(city)}.json`, {
      params: {
        access_token: '你的Mapbox令牌',
        types: 'poi.park,poi.lake', // 按需调整类型
        limit: 10 // 限制返回结果数量,减少冗余
      }
    });

    // 过滤提取核心景点信息
    const cleanAttractions = apiRes.data.features.map(item => ({
      name: item.text,
      fullAddress: item.place_name,
      coordinates: item.center,
      category: item.properties?.category || '未分类'
    }));

    console.log(cleanAttractions);
    return cleanAttractions;
  } catch (err) {
    console.error('请求失败:', err.response?.data.message || err.message);
  }
}

二、过滤冗余响应数据

Mapbox原始响应包含大量元数据,只需从features数组提取所需字段即可。上面的代码通过map方法筛选出名称、地址、坐标、分类等核心信息,完全剔除冗余内容。

三、React前端交互示例

import { useState } from 'react';

function AttractionFinder() {
  const [inputCity, setInputCity] = useState('');
  const [attractions, setAttractions] = useState([]);

  const handleSearch = async () => {
    if (!inputCity.trim()) return;
    try {
      const res = await fetch(`/api/attractions?city=${encodeURIComponent(inputCity)}`);
      const data = await res.json();
      setAttractions(data);
    } catch (err) {
      console.error('搜索出错:', err);
    }
  };

  return (
    <div className="search-container">
      <input
        type="text"
        value={inputCity}
        onChange={(e) => setInputCity(e.target.value)}
        placeholder="输入城市名"
      />
      <button onClick={handleSearch}>获取景点</button>
      <ul className="attraction-list">
        {attractions.map((item, index) => (
          <li key={index}>
            <h4>{item.name}</h4>
            <p>{item.fullAddress}</p>
            <span>类型: {item.category}</span>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default AttractionFinder;

四、Node.js后端代理路由(Express)

const express = require('express');
const router = express.Router();
const axios = require('axios');

// 从环境变量读取令牌,避免硬编码泄露
const MAPBOX_TOKEN = process.env.MAPBOX_ACCESS_TOKEN;

router.get('/attractions', async (req, res) => {
  const { city } = req.query;
  if (!city) return res.status(400).json({ error: '请提供城市名称' });

  try {
    const apiRes = await axios.get(`https://api.mapbox.com/geocoding/v5/mapbox.places/${encodeURIComponent(city)}.json`, {
      params: {
        access_token: MAPBOX_TOKEN,
        types: 'poi.park,poi.lake',
        limit: 10
      }
    });

    const filteredData = apiRes.data.features.map(item => ({
      name: item.text,
      fullAddress: item.place_name,
      category: item.properties?.category || '未分类'
    }));

    res.json(filteredData);
  } catch (err) {
    res.status(err.response?.status || 500).json({
      error: err.response?.data.message || '获取景点失败'
    });
  }
});

module.exports = router;

关键注意事项

  • 绝对不要在前端代码中暴露Mapbox令牌,必须通过后端代理请求,防止令牌被盗用
  • 若需要更精准的结果,可以先获取城市的边界范围(用Mapbox反向地理编码),再通过bbox参数限定搜索范围,避免返回其他城市的景点
  • 可根据需求扩展types参数,比如添加poi.museum、poi.historical_landmark等具体类型

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 19:47:09