当前位置:网站首页>golang源码分析之geoip2-golang
golang源码分析之geoip2-golang
2022-08-02 19:47:00 【用户9710217】
https://github.com/oschwald/geoip2-golang用来解析
[GeoLite2](http://dev.maxmind.com/geoip/geoip2/geolite2/)
and [GeoIP2](http://www.maxmind.com/en/geolocation_landing)数据库的一个工具包。类似于nginx的https://github.com/leev/ngx_http_geoip2_module
GeoIP2数据库有什么用呢?我们可以根据ip来获取ip的地理位置信息然后做响应的地域相关的业务:
1,简单的cdn,根据ip的地理信息重定向到合适的cdn服务器
2,做固定区域的业务屏蔽,比如:不给日本的用户提供服务
3,做国际化,根据不同的地域提供不同语言的服务。
比如我们常用的网络工具https://github.com/zu1k/nali 其实就用到了geoip2-golang这个包来解析GeoIP2数据。下面,我们看下这个包应该如何使用:
package main
import (
"fmt"
"log"
"net"
"github.com/oschwald/geoip2-golang"
)
func main() {
db, err := geoip2.Open("./GeoLite2-City.mmdb")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// If you are using strings that may be invalid, check that ip is not nil
ip := net.ParseIP("180.101.49.12") //120.24.37.249
record, err := db.City(ip)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Portuguese (BR) city name: %v\n", record.City.Names["zh-CN"])
fmt.Printf("English subdivision name: %v\n", record.Subdivisions[0].Names["en"])
fmt.Printf("Russian country name: %v\n", record.Country.Names["en"])
fmt.Printf("ISO country code: %v\n", record.Country.IsoCode)
fmt.Printf("Time zone: %v\n", record.Location.TimeZone)
fmt.Printf("Coordinates: %v, %v\n", record.Location.Latitude, record.Location.Longitude)
// Output:
// Portuguese (BR) city name: Londres
// English subdivision name: England
// Russian country name: Великобритания
// ISO country code: GB
// Time zone: Europe/London
// Coordinates: 51.5142, -0.0931
}非常简单,加载GeoLite2-City.mmdb数据库,解析ip地址,通过ip地址加载城市信息。
接着,我们详细分析下geoip2-golang这个包的源码。它的源码很简单只有一个文件:
reader.go调用了maxminddb数据解析包github.com/oschwald/maxminddb-golang来做 数据的解析,仅仅做了一层接口上的封装,和对应地理数据格式(企业、城市、国家、AnonymousIP、Domain、ISP)的定义。
比如城市信息:
// The City struct corresponds to the data in the GeoIP2/GeoLite2 City
// databases.
type City struct {
City struct {
GeoNameID uint `maxminddb:"geoname_id"`
Names map[string]string `maxminddb:"names"`
} `maxminddb:"city"`
Continent struct {
Code string `maxminddb:"code"`
GeoNameID uint `maxminddb:"geoname_id"`
Names map[string]string `maxminddb:"names"`
} `maxminddb:"continent"`
Country struct {
GeoNameID uint `maxminddb:"geoname_id"`
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
IsoCode string `maxminddb:"iso_code"`
Names map[string]string `maxminddb:"names"`
} `maxminddb:"country"`
Location struct {
AccuracyRadius uint16 `maxminddb:"accuracy_radius"`
Latitude float64 `maxminddb:"latitude"`
Longitude float64 `maxminddb:"longitude"`
MetroCode uint `maxminddb:"metro_code"`
TimeZone string `maxminddb:"time_zone"`
} `maxminddb:"location"`
Postal struct {
Code string `maxminddb:"code"`
} `maxminddb:"postal"`
RegisteredCountry struct {
GeoNameID uint `maxminddb:"geoname_id"`
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
IsoCode string `maxminddb:"iso_code"`
Names map[string]string `maxminddb:"names"`
} `maxminddb:"registered_country"`
RepresentedCountry struct {
GeoNameID uint `maxminddb:"geoname_id"`
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
IsoCode string `maxminddb:"iso_code"`
Names map[string]string `maxminddb:"names"`
Type string `maxminddb:"type"`
} `maxminddb:"represented_country"`
Subdivisions []struct {
GeoNameID uint `maxminddb:"geoname_id"`
IsoCode string `maxminddb:"iso_code"`
Names map[string]string `maxminddb:"names"`
} `maxminddb:"subdivisions"`
Traits struct {
IsAnonymousProxy bool `maxminddb:"is_anonymous_proxy"`
IsSatelliteProvider bool `maxminddb:"is_satellite_provider"`
} `maxminddb:"traits"`
}先看下open函数
func Open(file string) (*Reader, error) {
reader, err := maxminddb.Open(file)
if err != nil {
return nil, err
}
dbType, err := getDBType(reader)
return &Reader{reader, dbType}, err
}它调用了 maxminddb.Open返回了一个Reader
type Reader struct {
mmdbReader *maxminddb.Reader
databaseType databaseType
}Reader上定义了City,County等函数
func (r *Reader) City(ipAddress net.IP) (*City, error) {
if isCity&r.databaseType == 0 {
return nil, InvalidMethodError{"City", r.Metadata().DatabaseType}
}
var city City
err := r.mmdbReader.Lookup(ipAddress, &city)
return &city, err
}这些函数也只是对mmdbReader.Lookup做了简单的封装。
边栏推荐
猜你喜欢
随机推荐
JWT学习
image could not be accessed on a registry to record its digest
4 kmiles join YiSheng group, with more strong ability of digital business, accelerate China's cross-border electricity full domain full growth
Redis集群配置
es DELETE index 源码分析
MySQL安装配置教程(超级详细、保姆级)
网络协议介绍
golang刷leetcode动态规划(11)不同路径
J9数字货币论:识别Web3新的稀缺性:开源开发者
一款好用的FAQ搭建工具
分布式事务
Leetcode刷题——单调栈问题(739每日温度问题、496下一个更大元素I、503下一个更大元素 II)
Cannot find declaration to go to
idea 配置resin
Five data structures of Redis and their corresponding usage scenarios
Parse the commonly used methods in the List interface that are overridden by subclasses
所谓武功再高也怕菜刀-分区、分库、分表和分布式的优劣
技术分享 | Apache Linkis 快速集成网页IDE工具 Scriptis
实现客户服务自助,打造产品知识库
【StoneDB性能相关工具】内存监控









