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

如何在服务器端用Golang从Google Maps短链接获取坐标?

解决Google Maps短链接转坐标的问题

你遇到的错误核心原因是:短链接的后缀(比如y2HccUDkhVjhWJWb8)并不是Google Geocoding API认可的PlaceID,直接把它传给ReverseGeocode肯定会触发参数无效的错误。

下面提供两种可行的服务器端Golang实现方案:

方案一:解析短链接跳转目标,直接提取坐标

Google Maps短链接(maps.app.goo.gl/xxx)本质是重定向链接,会跳转到包含坐标或PlaceID的完整Google Maps URL。我们可以先通过HTTP请求获取跳转后的真实URL,再从中提取坐标信息。

代码示例

package main

import (
	"fmt"
	"log"
	"net/http"
	"net/url"
	"strings"
)

// 获取短链接跳转后的最终URL
func resolveShortLink(shortURL string) (string, error) {
	client := &http.Client{
		// 禁用自动跟随重定向,手动处理以便获取Location头
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return http.ErrUseLastResponse
		},
	}

	req, err := http.NewRequest(http.MethodHead, shortURL, nil)
	if err != nil {
		return "", err
	}

	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	// 处理3xx重定向状态码
	if resp.StatusCode >= 300 && resp.StatusCode < 400 {
		return resp.Header.Get("Location"), nil
	}

	return "", fmt.Errorf("no redirect found for %s", shortURL)
}

// 从Google Maps URL中提取坐标
func extractCoordinatesFromURL(mapsURL string) (float64, float64, error) {
	parsedURL, err := url.Parse(mapsURL)
	if err != nil {
		return 0, 0, err
	}

	// 情况1:URL包含lat和lng参数
	latStr := parsedURL.Query().Get("lat")
	lngStr := parsedURL.Query().Get("lng")
	if latStr != "" && lngStr != "" {
		var lat, lng float64
		fmt.Sscanf(latStr, "%f", &lat)
		fmt.Sscanf(lngStr, "%f", &lng)
		return lat, lng, nil
	}

	// 情况2:URL路径包含坐标(比如/place/.../@lat,lng,...)
	pathParts := strings.Split(parsedURL.Path, "/")
	for _, part := range pathParts {
		if strings.HasPrefix(part, "@") {
			coordPart := strings.TrimPrefix(part, "@")
			coordSegments := strings.Split(coordPart, ",")
			if len(coordSegments) >= 2 {
				var lat, lng float64
				fmt.Sscanf(coordSegments[0], "%f", &lat)
				fmt.Sscanf(coordSegments[1], "%f", &lng)
				return lat, lng, nil
			}
		}
	}

	return 0, 0, fmt.Errorf("no coordinates found in URL %s", mapsURL)
}

func main() {
	shortLinks := []string{
		"https://maps.app.goo.gl/y2HccUDkhVjhWJWb8",
		"https://maps.app.goo.gl/6LRg48ifPQGau8bV7",
		"https://maps.app.goo.gl/rB4hNMWWczsQ58FP9",
	}

	for _, link := range shortLinks {
		finalURL, err := resolveShortLink(link)
		if err != nil {
			log.Printf("Failed to resolve %s: %v", link, err)
			continue
		}

		lat, lng, err := extractCoordinatesFromURL(finalURL)
		if err != nil {
			log.Printf("Failed to extract coordinates from %s: %v", finalURL, err)
			continue
		}

		fmt.Printf("Short link %s -> Coordinates: %.6f, %.6f\n", link, lat, lng)
	}
}

方案二:解析跳转URL获取PlaceID,再调用Geocoding API

如果需要更详细的地址信息,而非仅坐标,可以从跳转后的URL中提取PlaceID,再通过Google Geocoding API的ReverseGeocode或Geocode接口获取完整数据。

代码示例(基于方案一扩展)

package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"strings"

	"github.com/googlemaps/google-maps-services-go/maps"
)

// 获取短链接跳转后的最终URL(复用方案一中的函数)
func resolveShortLink(shortURL string) (string, error) {
	client := &http.Client{
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return http.ErrUseLastResponse
		},
	}

	req, err := http.NewRequest(http.MethodHead, shortURL, nil)
	if err != nil {
		return "", err
	}

	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 300 && resp.StatusCode < 400 {
		return resp.Header.Get("Location"), nil
	}

	return "", fmt.Errorf("no redirect found for %s", shortURL)
}

// 从URL中提取PlaceID
func extractPlaceIDFromURL(mapsURL string) (string, error) {
	parsedURL, err := url.Parse(mapsURL)
	if err != nil {
		return "", err
	}

	// 情况1:URL包含place_id参数
	placeID := parsedURL.Query().Get("place_id")
	if placeID != "" {
		return placeID, nil
	}

	// 情况2:URL路径包含place_id(比如/place/PlaceName/place_id:xxx/...)
	path := parsedURL.Path
	if strings.Contains(path, "place_id:") {
		startIdx := strings.Index(path, "place_id:") + len("place_id:")
		endIdx := strings.Index(path[startIdx:], "/")
		if endIdx != -1 {
			return path[startIdx : startIdx+endIdx], nil
		}
		return path[startIdx:], nil
	}

	return "", fmt.Errorf("no place_id found in URL %s", mapsURL)
}

func main() {
	myAPIKey := "YOUR_GOOGLE_MAPS_API_KEY"
	shortLinks := []string{
		"https://maps.app.goo.gl/y2HccUDkhVjhWJWb8",
		"https://maps.app.goo.gl/6LRg48ifPQGau8bV7",
		"https://maps.app.goo.gl/rB4hNMWWczsQ58FP9",
	}

	// 初始化Geocoding客户端
	c, err := maps.NewClient(maps.WithAPIKey(myAPIKey))
	if err != nil {
		log.Fatalf("Failed to create maps client: %v", err)
	}

	for _, link := range shortLinks {
		finalURL, err := resolveShortLink(link)
		if err != nil {
			log.Printf("Failed to resolve %s: %v", link, err)
			continue
		}

		placeID, err := extractPlaceIDFromURL(finalURL)
		if err != nil {
			log.Printf("Failed to extract place_id from %s: %v", finalURL, err)
			continue
		}

		// 调用ReverseGeocode获取详细信息
		r := &maps.GeocodingRequest{
			PlaceID: placeID,
		}
		resp, err := c.ReverseGeocode(context.Background(), r)
		if err != nil {
			log.Printf("Failed to reverse geocode place_id %s: %v", placeID, err)
			continue
		}

		if len(resp) > 0 {
			location := resp[0].Geometry.Location
			fmt.Printf("Short link %s -> Coordinates: %.6f, %.6f\n", link, location.Lat, location.Lng)
			fmt.Printf("Address: %s\n", resp[0].FormattedAddress)
		}
	}
}

注意事项

  1. 确保你的Google Maps API Key已启用Geocoding API权限,否则会触发权限错误。
  2. 处理短链接时,若存在多次重定向,可修改resolveShortLink函数实现自动跟随所有重定向直到最终URL。
  3. Google Maps的URL格式可能会有变化,需要定期维护解析逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 12:27:29