使用Go语言实现了一个适用于Qt Map的Google瓦片服务器,无需翻墙,并添加了家庭路由器IP获取功能。

Go语言实现的HTTP代理服务器及IP获取功能

本文将介绍一段使用Go语言编写的HTTP代理服务器代码,以及其中的关键部分。该代码可以将OpenStreetMap(OSM)的瓦片请求URL转换为Google地图的代理请求URL,并提供一个用于获取家用路由器公网IP地址的功能。通过详细解析代码实现和应用场景,读者将了解到HTTP代理服务器的基本原理、如何转换URL格式以实现代理功能,以及如何利用家用路由器获取公网IP的实际应用。

实现HTTP代理服务器

在这部分中,我们将详细解析代码,了解如何通过HTTP代理服务器将OpenStreetMap(OSM)的瓦片请求URL转换为Google地图的代理请求URL。首先,我们需要了解HTTP代理服务器的工作原理和基本概念。

HTTP代理服务器是一个位于客户端和目标服务器之间的中间服务器,它接收客户端发起的HTTP请求,并将请求转发给目标服务器。在本例中,我们使用Go语言编写的HTTP代理服务器将接收来自客户端的请求,并将其转发给Google地图服务器。

关键代码段:

func handleRequest(w http.ResponseWriter, r *http.Request) {
    // 解析路径
    path := r.URL.Path
    // 移除路径前缀和文件扩展名
    path = strings.TrimPrefix(path, "/google/")
    path = strings.TrimSuffix(path, ".png")

    // 拆分路径中的参数
    params := strings.Split(path, "/")
    if len(params) != 3 {
        http.Error(w, "Invalid path", http.StatusBadRequest)
        return
    }

    // 获取参数值
    z := params[0]
    x := params[1]
    y := params[2]

    // 构建转发的 URL
    forwardURL := fmt.Sprintf("https://gac-geo.googlecnapps.cn/maps/vt?lyrs=s&x=%s&y=%s&z=%s",
        x, y, z)

    // 创建新的 HTTP 请求,并将 URL 设置为转发的 URL
    req, err := http.NewRequest("GET", forwardURL, nil)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    // 发送 HTTP 请求
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    defer resp.Body.Close()

    // 读取响应内容
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    // 将响应内容写入到 HTTP 响应中
    w.Header().Set("Content-Type", "image/png")
    w.Write(body)
}

在上述代码中,我们定义了一个名为handleRequest的函数,用于处理客户端的HTTP请求。首先,我们从URL路径中解析出需要的参数xyz,这些参数表示地图瓦片的坐标。然后,我们构建了一个转发的URL,将这些参数插入到Google地图代理请求URL的相应位置。

接下来,我们使用http.NewRequest函数创建一个新的HTTP请求对象,其中包含转发的URL。然后,我们使用http.Client发送该请求,并获取响应。最后,我们从响应中读取内容,并将其写入到HTTP响应中,以返回给客户端。

通过这段代码,我们可以实现将OpenStreetMap(OSM)的瓦片请求URL转换为Google地图的代理请求URL,并将代理服务器的响应返回给客户端。

IP获取功能的应用场景

在这部分中,我们将介绍代码中的另一个功能,即通过家用路由器获取公网IP地址的应用场景。我们将探讨家用路由器获取公网IP的意义,以及如何在代码中实现这一功能。

家用路由器通常会分配一个内部IP地址给每个连接到它的设备,这些设备可以通过该IP地址在局域网内进行通信。然而,这个内部IP地址无法用于访问Internet上的其他设备,因为它不是唯一的并且没有在全球范围内注册。

为了实现Internet访问,我们需要知道家用路由器的公网IP地址。公网IP地址是唯一的,并且可以在Internet上进行标识和路由。在本例中,我们使用了一个名为pingHandler的函数来获取家用路由器的公网IP地址。

关键代码段:

type IPResponse struct {
    IPv4 string `json:"ipv4"`
}

func pingHandler(w http.ResponseWriter, r *http.Request) {
    ip, _, err := net.SplitHostPort(r.RemoteAddr)
    if err != nil {
        http.Error(w, "Failed to get IP address", http.StatusInternalServerError)
        return
    }

    ipv4 := net.ParseIP(ip).To4()
    if ipv4 == nil {
        http.Error(w, "Failed to parse IPv4 address", http.StatusInternalServerError)
        return
    }

    response := IPResponse{
        IPv4: ipv4.String(),
    }

    jsonData, err := json.Marshal(response)
    if err != nil {
        http.Error(w, "Failed to marshal JSON", http.StatusInternalServerError)
        return
    }

    w.Header().Set("Content-Type", "application/json")
    w.Write(jsonData)
}

在上述代码中,我们定义了一个名为pingHandler的函数,用于处理客户端的/ping/路径请求。该函数通过解析r.RemoteAddr来获取客户端的IP地址。然后,我们使用net.ParseIP函数将IP地址解析为IPv4地址。如果解析失败,我们将返回一个错误响应。

接下来,我们创建一个IPResponse结构体,用于存储IP地址,并将其转换为JSON格式。最后,我们将JSON数据写入HTTP响应中,并返回给客户端。

通过这段代码,我们可以在访问/ping/路径时获取家用路由器的公网IP地址,这在某些应用场景下非常有用,例如需要知道家庭网络的公网IP地址来进行远程访问或网络配置。

完整代码

main.go

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"strings"
)

type IPResponse struct {
	IPv4 string `json:"ipv4"`
}

func pingHandler(w http.ResponseWriter, r *http.Request) {
	ip, _, err := net.SplitHostPort(r.RemoteAddr)
	if err != nil {
		http.Error(w, "Failed to get IP address", http.StatusInternalServerError)
		return
	}

	ipv4 := net.ParseIP(ip).To4()
	if ipv4 == nil {
		http.Error(w, "Failed to parse IPv4 address", http.StatusInternalServerError)
		return
	}

	response := IPResponse{
		IPv4: ipv4.String(),
	}

	jsonData, err := json.Marshal(response)
	if err != nil {
		http.Error(w, "Failed to marshal JSON", http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(jsonData)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
	// 解析路径
	path := r.URL.Path
	// 移除路径前缀和文件扩展名
	path = strings.TrimPrefix(path, "/google/")
	path = strings.TrimSuffix(path, ".png")

	// 拆分路径中的参数
	params := strings.Split(path, "/")
	if len(params) != 3 {
		http.Error(w, "Invalid path", http.StatusBadRequest)
		return
	}

	// 获取参数值
	x := params[0]
	y := params[1]
	z := params[2]

	// 构建转发的 URL
	forwardURL := fmt.Sprintf("https://gac-geo.googlecnapps.cn/maps/vt?lyrs=s&x=%s&y=%s&z=%s",
		x, y, z)

	// 创建新的 HTTP 请求,并将 URL 设置为转发的 URL
	req, err := http.NewRequest("GET", forwardURL, nil)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// 发送 HTTP 请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer resp.Body.Close()

	// 读取响应内容
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// 将响应内容写入到 HTTP 响应中
	w.Header().Set("Content-Type", "image/png")
	w.Write(body)
}

func main() {
	http.HandleFunc("/google/", handleRequest)
	http.HandleFunc("/ping/", pingHandler)
	log.Println("http://localhost:10000/google/x/y/z.png")
	log.Println("http://localhost:10000/ping")
	log.Fatal(http.ListenAndServe(":10000", nil))
}

编译 linux 和 windows 平台。
GOOS=linux GOARCH=amd64 go build -o proxy-server-linux main.go
GOOS=windows GOARCH=amd64 go build -o proxy-server-windows.exe main.go

在 Qt Map 中如何使用?

Qt 5.15

import QtQuick 5.15
import QtLocation 5.15
import QtPositioning 5.15

Window {
    width:640
    height:480
    visible: true
    Map {
        id: map
        anchors.fill: parent
        plugin: Plugin {
            name: "osm"
            PluginParameter {
                name: "osm.mapping.custom.host"
                value: "http://localhost:10000/google/"
            }
        }
        activeMapType: map.supportedMapTypes[map.supportedMapTypes.length - 1]
        center: QtPositioning.coordinate(22.53, 114.04)
        minimumZoomLevel: 5
        maximumZoomLevel: 19
        zoomLevel: 13
    }
}

Qt 6.5

import QtQuick
import QtLocation
import QtPositioning

Window {
    width: 640
    height: 480
    visible: true
    MapView {
        anchors.fill: parent
        minimumZoomLevel: 5
        maximumZoomLevel: 19
        map {
            plugin: Plugin {
                name: "osm"
                PluginParameter {
                    name: "osm.mapping.custom.host"
                    value: "http://localhost:10000/google/"
                }
                PluginParameter {
                    name: "osm.mapping.providersrepository.disabled"
                    value: true
                }
            }
            zoomLevel: 13
            opacity: 0.999
            activeMapType: map.supportedMapTypes[map.supportedMapTypes.length - 1]
            center: QtPositioning.coordinate(22.53, 114.04)
        }
    }
}

总结

本文介绍了一段使用Go语言实现的HTTP代理服务器代码,以及其中的关键部分。我们详细解析了代码中的URL转换和代理功能实现,以及家用路由器获取公网IP的应用场景。通过深入分析代码,读者可以了解HTTP代理服务器的基本原理、URL格式转换的实现方法,以及家用路由器获取公网IP的实际应用。

本文主要内容包括:

  1. HTTP代理服务器的原理和概念
  2. 通过Go语言实现的HTTP代理服务器代码解析
  3. URL格式转换实现的关键代码解析
  4. 家用路由器获取公网IP的应用场景介绍
  5. 使用Go语言获取家用路由器公网IP的代码解析

通过本文的阅读,读者将了解到如何通过Go语言编写一个简单的HTTP代理服务器,并了解到该服务器的URL转换功能和家用路由器获取公网IP的应用场景。这对于理解HTTP代理服务器的工作原理、实现自定义代理功能以及应用家用路由器的公网IP获取功能都是非常有价值的。

扩展

如果你想在 windows 系统以服务的方式运行,请添加 _ "github.com/kardianos/minwinsvc" ,然后使用下面命令管理windows服务。

sc create <服务名称> binPath= "<可执行文件路径>"
sc start <服务名称>
sc stop <服务名称>
sc delete <服务名称>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cheungxiongwei.com

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值