简体   繁体   English

请求实体太大-Google Map Directions错误413

[英]Request entity too large - google map directions error 413

First, I want to say I'm not too experienced with Google Maps Javascript API v3 (my only experience are these last 3 days). 首先,我想说的是我对Google Maps Javascript API v3使用不太熟悉(我的唯一经历是最近3天)。 I have managed to display a map with a list of markers and connect them using DirectionsService , but sometimes my list is pretty large and I get the following error: 我设法显示了一个带有标记列表的DirectionsService ,并使用DirectionsService将它们连接起来,但是有时我的列表很大,并且出现以下错误:

Failed to load resource: the server responded with a status of 413 (Request Entity Too Large)

This is my code: 这是我的代码:

// List of all locations for device 
var locations = [];
// example: locations = [
//     {datetime: '2014/09/28 20:20', location: '41.99999 21.99999 30.0'},
//     ... {...} ... may be more than 200 entries for locations
//     {datetime: '2014/09/28 20:25', location: '41.99999 21.99999 30.0'}
// ]

var map;
var markers = [];
var bounds = new google.maps.LatLngBounds();
var pathPoints = [];
var infoWindow = new google.maps.InfoWindow();
var accuracy = new google.maps.Circle({
    fillColor: '#ff4080',
    fillOpacity: 0.5,
    strokeOpacity: 0,
    zIndex: 0
});
var path = new google.maps.Polyline(polyOptions);
var geocoder;
var directionsService = new google.maps.DirectionsService();
var directionsDisplay;
var polyOptions = {
    geodesic: true,
    strokeColor: '#28b8b8',
    strokeOpacity: 1.0,
    strokeWeight: 8,
    zIndex: 1
}
function showInfoWindow(marker, datetime, acc){
    geocoder = new google.maps.Geocoder();
    geocoder.geocode({
        'latLng': marker.getPosition()
    }, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
            if (results[1]) {
                infoWindow.close();
                var date = datetime.split(" ")[0];
                var time = datetime.split(" ")[1];
                var content = '<div class="infowindow">'
                        + results[1].formatted_address.trim() + '<br />'
                        + 'Date: ' + date + '<br />'
                        + 'Time: ' + time + '<br />'
                        + 'Accuracy: ' + acc + 'm'
                        + '</div>';
                infoWindow.setContent(content);
                infoWindow.open(map, marker);
                accuracy.setMap(null);
                accuracy.setMap(map);
                accuracy.setCenter(marker.getPosition());
                accuracy.setRadius(acc/1.6);
            } else {
                // alert('No results found');
            }
        } else {
            alert('Geocoder failed due to: ' + status);
        }
    });
}
function addMultiMarker(latLng, num, datetime, acc){
    // Create marker at provided location
    var marker = new google.maps.Marker({
        position: latLng,
        map: map,
        icon: image_circle,
        title: 'Location #' + num,
        zIndex: num + 1
    });
    // On marker click center it inside map and show infoWindow
    google.maps.event.addListener(marker, 'click', function() {
        map.panTo(marker.getPosition());
        showInfoWindow(marker, datetime, acc);
    });
    return marker;
}
function showRoute() {
    var rendererOptions = {
        draggable: false,
        hideRouteList: true,
        suppressMarkers: true,
        infoWindow: infoWindow,
        polylineOptions: polyOptions,
        map: map
    };
    directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);
    var len = markers.length;
    var start = markers[0].getPosition();
    var end = markers[len - 1].getPosition();
    new google.maps.event.trigger(markers[len - 1], 'click');
    var wayPts = [];
    for(var i = 1; i < len - 1; i++){
        wayPts.push({
            location: markers[i].getPosition(),
            stopover: true
        });
    }
    var request = {
        origin: start,
        destination: end,
        waypoints: wayPts,
        optimizeWaypoints: true,
        travelMode: google.maps.TravelMode.DRIVING
    };
    directionsService.route(request, function(response, status) {
        if (status == google.maps.DirectionsStatus.OK) {
            directionsDisplay.setDirections(response);
        }
    });
}
function showMapPeriod(periodStart, periodEnd){
    // Simple map options
    var mapOptions = {
        zoom: 15,
        center: new google.maps.LatLng(41, 21),
        mapTypeId : google.maps.MapTypeId.ROADMAP,
        mapTypeControl: true,
        mapTypeControlOptions: {
            style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
            position: google.maps.ControlPosition.TOP_RIGHT
        },
        zoomControl: true,
        zoomControlOptions: {
            style: google.maps.ZoomControlStyle.LARGE,
            position: google.maps.ControlPosition.LEFT_CENTER
        },
        panControl: false,
        streetViewControl: false
    };
    $("#map").html("");
    // Create and show map
    openMapContainer(); // just a function that shows the map <div> element
    map = new google.maps.Map(document.getElementById('map'), mapOptions);
    // Create and display markers
    bounds = new google.maps.LatLngBounds();
    markers = [];
    var len = 0;
    for(var i = periodStart; i <= periodEnd; i++, len++){
        var loc_vals = locations[i].location.trim().split(" ");
        var lat = parseFloat(loc_vals[0]);
        var lng = parseFloat(loc_vals[1]);
        var acc = parseFloat(loc_vals[2]);
        // Create marker at provided location
        var datetime = locations[i].datetime;
        var latLng = new google.maps.LatLng(lat, lng);
        markers[len] = addMultiMarker(latLng, len+1, datetime, acc);
        bounds.extend(latLng);
    }
    showRoute();
    map.fitBounds(bounds);
}

Well my code works partially and if someone can help me to eliminate the problem I would very much appreciate it. 好吧,我的代码部分起作用,如果有人可以帮助我消除问题,我将非常感激。 To explain it better, I need some kind of solution to request Directions with a lot (200+) waypoints or some way to connect the locations through the roads (I don't really need the directions, but I don't want to connect the locations with a simple Polyline ). 为了更好地解释它,我需要某种解决方案来请求具有很多(200+)航路点的Directions ,或者通过某种方式来连接道路位置(我并不需要方向,但是我不想连接用简单的Polyline定位位置)。

EDIT: Here I have provided a simple demo, to see the problem just uncomment at line 15 . 编辑: 在这里我提供了一个简单的演示,以查看问题只是在line 15注释。

Since nobody was able to help me with my problem, I had to solve it myself. 由于没有人能够帮助我解决问题,因此我必须自己解决问题。 I'm answering my own question because this seems to be quite a problem for a lot of people and it's not well enough explained on the web, so this may help developers that have similar problems. 我正在回答自己的问题,因为这对很多人来说都是个问题,并且在网络上解释得还不够,因此这可能会对有类似问题的开发人员有所帮助。

Anyway, let's get to the point. 无论如何,让我们说清楚。 The error was thrown because of Google limitations as OxyDesign suggested, the error was: 该错误是由于OxyDesign建议的Google限制而引发的 ,错误为:

  • google.maps.DirectionsResult.MAX_WAYPOINTS_EXCEEDED - This is because I sent a request with origin , destination and more than 8 (Google limit) waypoints . google.maps.DirectionsResult.MAX_WAYPOINTS_EXCEEDED这是因为我发送了一个包含起点目的地和8个以上(Google限制) 航路点的请求。

that I easily solved (I just split the array in chunks of 10 points with the last point of one request as the first point of the next), but then I got another error: 我很容易解决的问题(我只是将数组分成10个点,将一个请求的最后一个点作为下一个请求的第一个点),但是随后出现另一个错误:

  • google.maps.DirectionsResult.OVER_QUERY_LIMIT - This is because I tried to send more than 10 (again, Google limit) requests per second. google.maps.DirectionsResult.OVER_QUERY_LIMIT这是因为我尝试每秒发送10个以上的请求(同样是Google的限制)。

that took a little more experimenting, searching and testing to solve, but I got it solved. 需要更多的实验,搜索和测试才能解决,但是我解决了。

Now, here is the code that works for me (at least at the time of posting, until Google changes something): 现在,这是对我有用的代码(至少在发布时,直到Google进行了一些更改):

// list of randomly generated locations (max 288)
var locations = [];
for(var i=0; i<288; i++){
    locations[i] = {
        datetime: '2014/10/01 12:10',
        location: (51 + Math.random()) +
        ' ' + (-0.5 + Math.random()) + ' 30.0'
    };
}
// Marker images
var image_pin = new google.maps.MarkerImage(
    'http://stedkomerc.com.mk/gpslocator/images/mPin.svg',  
    new google.maps.Size(25, 41),  // size
    new google.maps.Point(0, 0),   // origin, top-left corner
    new google.maps.Point(12, 40)  // anchor
);
var image_circle = new google.maps.MarkerImage(
    'http://stedkomerc.com.mk/gpslocator/images/mCircle.svg',
    new google.maps.Size(19, 19),  // size
    new google.maps.Point(0, 0),   // origin, top-left corner
    new google.maps.Point(9, 9)    // anchor
);
// Variables
var map;
var bounds = new google.maps.LatLngBounds();
var markers = [];
var pathPoints = [];
var geocoder;
var infoWindow = new google.maps.InfoWindow();
var accuracy = new google.maps.Circle({
    fillColor: '#ff4080',
    fillOpacity: 0.4,
    strokeOpacity: 0,
    zIndex: 0
});
var polyOptions = {
    geodesic: true,
    strokeColor: '#28b8b8',
    strokeOpacity: 1.0,
    strokeWeight: 8,
    zIndex: 1
};
var path = new google.maps.Polyline(polyOptions);
var directionsService = new google.maps.DirectionsService();
var directions = [];
var rendererOptions = {
    draggable: false,
    hideRouteList: true,
    suppressMarkers: true,
    preserveViewport: true,
    infoWindow: infoWindow,
    polylineOptions: polyOptions
};
var requests = [];
var MAX_POINTS_PER_REQUEST = 10; // 8*waypts Google limit + start + end
var MAX_REQUESTS_PER_SECOND = 10; // Google limit
// functions
function showInfoWindow(marker, datetime, acc){
    geocoder = new google.maps.Geocoder();
    geocoder.geocode({
        'latLng': marker.getPosition()
    }, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
            if (results[1]) {
                infoWindow.close();
                var date = datetime.split(" ")[0];
                var time = datetime.split(" ")[1];
                var content = '<div class="infowindow">' +
                    results[1].formatted_address.trim() + '<br />' +
                    'Date: ' + date + '<br />' +
                    'Time: ' + time + '<br />' +
                    'Accuracy: ' + acc + 'm' +
                    '</div>';
                infoWindow.setContent(content);
                infoWindow.open(map, marker);
                accuracy.setMap(null);
                accuracy.setMap(map);
                accuracy.setCenter(marker.getPosition());
                accuracy.setRadius(acc);
            }
        } else {
            console.log('Geocoder failed due to: ' + status);
        }
    });
}
function addMultiMarker(latLng, num, datetime, acc){
    // Create marker at provided location
    var marker = new google.maps.Marker({
        position: latLng,
        map: map,
        icon: image_circle,
        title: 'Location #' + num,
        zIndex: num + 1
    });
    // On marker click center it inside map and show infoWindow
    google.maps.event.addListener(marker, 'click', function() {
        //map.panTo(marker.getPosition());
        showInfoWindow(marker, datetime, acc);
    });
    return marker;
}
function connectMarkersPolyline(mrkrs){
    path.setMap(map);
    pathPoints = path.getPath();
    len = mrkrs.length;
    for(var i = 0; i < len; i++){
        pathPoints.push(mrkrs[i].getPosition());
    }
}
function connectMarkersRoute(mrkrs, part, maxParts){
    var directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);
    directionsDisplay.setMap(map);
    var len = mrkrs.length;
    var start = mrkrs[0].getPosition();
    var end = mrkrs[len - 1].getPosition();
    var wayPts = [];
    for(var i = 1; i < len - 1; i++){
        wayPts.push({
            location: mrkrs[i].getPosition(),
            stopover: true
        });
    }
    var request = {
        origin: start,
        destination: end,
        waypoints: wayPts,
        optimizeWaypoints: false,
        travelMode: google.maps.TravelMode.DRIVING,
        unitSystem: google.maps.UnitSystem.METRIC
    };
    directionsService.route(request, function(response, status) {
        if (status == google.maps.DirectionsStatus.OK) {
            // request status OK, display route
            directionsDisplay.setDirections(response);
            // save it in array in case we want to remove it later
            directions.push(directionsDisplay);
            // if not last chunk, send next chunk after 100ms
            // 1 request per 100ms => 10 requests per 1s
            if(part+1 < maxParts)
                setTimeout(connectMarkersRoute(requests[part+1], part+1, maxParts), 100);
            else showLastMarker();
        } else if (status == google.maps.DirectionsStatus.OVER_QUERY_LIMIT) {
            // if we get error, send same request after bigger delay (120ms)
            setTimeout(connectMarkersRoute(requests[part], part, maxParts), 120);
        } else {
            // if all fails, connect with simple polyline
            console.log('Directions failed due to: ' + status);
            connectMarkersPolyline(mrkrs);
        }
    });
}
function connectMarkers(markers){
    path.setMap(null);
    path.setPath([]);
    directions = [];
    requests = [];
    var len = markers.length;
    console.log('connecting ' + len + ' markers');
    var i, j;
    // split markers array into chunks of 10 (start + waypts + end)
    for(i=0; i<len; i+=MAX_POINTS_PER_REQUEST-1){
        if(i<len-1)
            requests.push(markers.slice(i, i+MAX_POINTS_PER_REQUEST));
    }
    // send first chunk to connectMarkersRoute()
    connectMarkersRoute(requests[0], 0, requests.length);
}
function showMapPeriod(periodStart, periodEnd){
    // Map options
    var mapOptions = {
        zoom: 16,
        center: new google.maps.LatLng(41.995922, 21.431465),
        mapTypeId : google.maps.MapTypeId.ROADMAP,
        mapTypeControl: true,
        mapTypeControlOptions: {
            style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
            position: google.maps.ControlPosition.TOP_RIGHT
        },
        zoomControl: true,
        zoomControlOptions: {
            style: google.maps.ZoomControlStyle.LARGE,
            position: google.maps.ControlPosition.LEFT_CENTER
        },
        panControl: false,
        streetViewControl: false
    };
    $("#map").html("");
    //openMapContainer();
    // Create and show map
    map = new google.maps.Map(document.getElementById('map'), mapOptions);
    // Create and display markers
    bounds = new google.maps.LatLngBounds();
    markers = [];
    var len = 0;
    for(var i = periodStart; i <= periodEnd; i++, len++){
        var loc_vals = locations[i].location.trim().split(" ");
        var lat = parseFloat(loc_vals[0]);
        var lng = parseFloat(loc_vals[1]);
        var acc = parseFloat(loc_vals[2]);
        // Create marker at provided location
        var datetime = locations[i].datetime;
        var latLng = new google.maps.LatLng(lat, lng);
        markers[len] = addMultiMarker(latLng, len+1, datetime, acc);
        bounds.extend(latLng);
    }
    connectMarkers(markers);
    map.fitBounds(bounds);
    if(map.getZoom() > 16) map.setZoom(16);  
}
function showLastMarker(){
    new google.maps.event.trigger(markers[markers.length - 1], 'click');  
}
// show map
showMapPeriod(1, 280);
// --------

As you can see, the only real change I made was the showRoute() function became connectMarkers() combined with connectMarkersRoute() and connectMarkersPolyline() that handle both errors. 正如你所看到的,我所做的唯一真正的变化是showRoute()函数成为connectMarkers()结合connectMarkersRoute()connectMarkersPolyline()是处理这两个错误。

Working example can be seen here . 工作示例可以在这里看到。 It takes a little time to load all route chunks, but at least it works. 加载所有路由块花费一些时间,但至少可以正常工作。 Hope this helps somebody else too. 希望这也会对其他人有所帮助。

Note that there is another Google limit of 2500 Directions requests per day, so be careful. 请注意,Google每天还有2500个Directions请求的限制,因此请注意。 That being said, this answer works even for a lot larger requests than 200 locations, I have tested with 1250 locations and it worked. 话虽如此,这个答案甚至适用于超过200个地点的更大请求,我已经在1250个地点进行了测试,并且有效。

这项服务的Gmaps Waypoints似乎有一个局限性(我尝试过823 ,直到39时才起作用,然后40才失效),除了折线以外,没有其他方法可以实现,但您不希望这样做我认为没有可行的解决方案...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM