package main import ( "bytes" "crypto/md5" "encoding/json" "fmt" "io" "net/http" "sort" "strings" ) const ( appKey = "DD3BZ-4643M-RJ76E-6WGEY-JZ4KO-2OBIG" appSK = "Px6Ig8s6ar0vFdnJXgcYoFvy4w3Z8wfr" apiURL = "https://apis.map.qq.com/ws/distance/v1/matrix" ) // 请求参数结构体 type RequestParams struct { Key string `json:"key"` From string `json:"from"` To string `json:"to"` Mode string `json:"mode"` } func main() { // 1. 原始参数 params := RequestParams{ Key: appKey, From: "39.940552,116.344101", // 北京展览馆 To: "39.916585,116.319596", // 中塔公园 Mode: "driving", } // 2. 取得结构体字段的排序后 kv 列表 kv, err := toSortedKV(params) if err != nil { panic(err) } // 3. 拼成 querystring(不含 sig),再追加 SK tosign := "/ws/distance/v1/matrix?" + kv + appSK fmt.Println("request query:", tosign) // 4. 计算 MD5(小写) sig := fmt.Sprintf("%x", md5.Sum([]byte(tosign))) // 5. 组装最终 URL finalURL := apiURL + "?sig=" + sig fmt.Println("request url:", finalURL) // 6. 发送 GET 请求 // 4. 发送 POST JSON jsonBytes, _ := json.Marshal(params) resp, err := http.Post(finalURL, "application/json", bytes.NewReader(jsonBytes)) defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Printf("status=%d\nbody=%s\n", resp.StatusCode, body) } // 按字段名升序拼成 key=value func toSortedKV(v interface{}) (string, error) { // 结构体转 map var m map[string]interface{} b, _ := json.Marshal(v) if err := json.Unmarshal(b, &m); err != nil { return "", err } keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } sort.Strings(keys) var sb strings.Builder for i, k := range keys { // 值 → 最短 JSON → 去首尾双引号 valBytes, _ := json.Marshal(m[k]) valStr := string(valBytes) if len(valStr) >= 2 && valStr[0] == '"' && valStr[len(valStr)-1] == '"' { valStr = valStr[1 : len(valStr)-1] } if i > 0 { sb.WriteByte('&') } sb.WriteString(k) sb.WriteByte('=') sb.WriteString(valStr) } return sb.String(), nil }