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

Flutter Map路线绘制报错:API响应无路线数据求助

Flutter Map 路线加载异常:No route data available in the API response

问题描述

使用Flutter框架开发,集成flutter_map、polylines、markers组件和OpenRouteService路线服务,运行代码后始终抛出异常:Error: Exception: No route data available in the API response。手动测试API密钥可正常获取路线数据,需排查问题原因。

代码示例

import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Future<List<LatLng>>? route;

  @override
  void initState() {
    super.initState();
    route = fetchRoute(
      LatLng(28.58256157514347, 77.32420983539001),
      LatLng(28.518005096303668, 77.38189447010934),
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Flutter Map Example')),
        body: FutureBuilder<List<LatLng>>(
          future: route,
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return Center(child: CircularProgressIndicator());
            } else if (snapshot.hasError) {
              return Center(child: Text('Error: ${snapshot.error}'));
            } else if (!snapshot.hasData || snapshot.data == null || snapshot.data!.isEmpty) {
              return Center(child: Text('No route data available'));
            } else {
              return FlutterMap(
                options: MapOptions(
                  initialCenter: LatLng(28.550283, 77.348052),
                  initialZoom: 12.0,
                ),
                children: [
                  TileLayer(
                    urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
                    userAgentPackageName: 'com.example.app',
                    maxZoom: 19.0,
                  ),
                  MarkerLayer(
                    markers: [
                      Marker(
                        point: LatLng(28.58256157514347, 77.32420983539001),
                        width: 80,
                        height: 80,
                        child: Container(
                          child: Icon(
                            Icons.pin_drop,
                            color: Colors.red,
                            size: 40,
                          ),
                        ),
                      ),
                      Marker(
                        point: LatLng(28.518005096303668, 77.38189447010934),
                        width: 80,
                        height: 80,
                        child: Container(
                          child: Icon(
                            Icons.pin_drop,
                            color: Colors.red,
                            size: 40,
                          ),
                        ),
                      ),
                    ],
                  ),
                  PolylineLayer(
                    polylines: [
                      Polyline(
                        points: snapshot.data!,
                        color: Colors.blue,
                        strokeWidth: 4.0,
                      ),
                    ],
                  ),
                ],
              );
            }
          },
        ),
      ),
    );
  }

  Future<List<LatLng>> fetchRoute(LatLng start, LatLng end) async {
    final apiKey = 'API KEY'; // Replace with your API key
    final url = 'https://api.openrouteservice.org/v2/directions/driving-car?api_key=$apiKey&start=${start.longitude},${start.latitude}&end=${end.longitude},${end.latitude}';

    final response = await http.get(Uri.parse(url));
    if (response.statusCode == 200) {
      final data = jsonDecode(response.body);

      print('API Response: $data');

      if (data['routes'] != null && data['routes'].isNotEmpty) {
        final route = data['routes'][0]['geometry']['coordinates'] as List;
        print('Route Coordinates: $route');

        return route.map((point) => LatLng(point[1], point[0])).toList();
      } else {
        throw Exception('No route data available in the API response');
      }
    } else {
      throw Exception('Failed to load route. Status code: ${response.statusCode}');
    }
  }
}

排查与解决建议

  1. 检查API响应的错误信息
    OpenRouteService即使返回200状态码,也可能在响应体中包含error字段(比如密钥权限不足、请求配额耗尽)。在解析前添加错误检查,能明确问题原因:

    if (data.containsKey('error')) {
      throw Exception('API错误: ${data['error']['message']}');
    }
    
  2. 验证JSON解析路径
    确认API返回的routes[0].geometry.coordinates结构是否符合预期。打印完整响应后,检查是否存在嵌套层级错误,可通过请求参数format=geojson确保返回标准GeoJSON结构。

  3. 添加层级存在性校验
    原代码直接访问data['routes'][0]['geometry']['coordinates'],若某一层级不存在会导致解析失败。增加逐层校验,避免空指针或结构不匹配:

    if (routeData['geometry'] != null && routeData['geometry']['coordinates'] != null) {
      final coordinates = routeData['geometry']['coordinates'] as List;
      return coordinates.map((point) => LatLng(point[1], point[0])).toList();
    } else {
      throw Exception('响应中缺少路线几何数据');
    }
    
  4. 确认网络权限配置
    检查Flutter项目的网络权限:

    • Android:在android/app/src/main/AndroidManifest.xml中添加<uses-permission android:name="android.permission.INTERNET"/>
    • iOS:确保Info.plist中未限制HTTPS请求(默认允许,无需额外配置)

修改后的fetchRoute函数示例

Future<List<LatLng>> fetchRoute(LatLng start, LatLng end) async {
  final apiKey = '你的API密钥';
  final url = 'https://api.openrouteservice.org/v2/directions/driving-car?api_key=$apiKey&start=${start.longitude},${start.latitude}&end=${end.longitude},${end.latitude}';

  final response = await http.get(Uri.parse(url));
  if (response.statusCode == 200) {
    final data = jsonDecode(response.body);

    // 优先检查API返回的错误信息
    if (data.containsKey('error')) {
      throw Exception('API错误: ${data['error']['message']}');
    }

    print('完整API响应: $data');

    if (data['routes'] != null && data['routes'].isNotEmpty) {
      final routeData = data['routes'][0];
      // 校验几何数据是否存在
      if (routeData['geometry'] != null && routeData['geometry']['coordinates'] != null) {
        final coordinates = routeData['geometry']['coordinates'] as List;
        return coordinates.map((point) => LatLng(point[1], point[0])).toList();
      } else {
        throw Exception('响应中缺少路线几何数据');
      }
    } else {
      throw Exception('API响应中无可用路线数据');
    }
  } else {
    throw Exception('加载路线失败,状态码: ${response.statusCode}');
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 18:15:58