当前位置:网站首页>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做了简单的封装。
边栏推荐
- 对话亚洲高校首个博士论文奖-裘捷中丨KDD2022
- Geoserver+mysql+openlayers2
- 4 kmiles join YiSheng group, with more strong ability of digital business, accelerate China's cross-border electricity full domain full growth
- PG's SQL execution plan
- 软考 ----- UML设计与分析(下)
- Triacetin是什么化学材料
- 【LeetCode】622. 设计循环队列
- 什么是乙二醇二乙酸酯(EGDA)?
- Lvm逻辑卷
- 银保监会:人身险产品信披材料应由保险公司总公司统一负责管理
猜你喜欢

4 kmiles join YiSheng group, with more strong ability of digital business, accelerate China's cross-border electricity full domain full growth

「面试必会」这应该是最有深度的TCP三次握手、四次挥手细节讲解

J9 Digital Currency Theory: Identifying Web3's New Scarcity: Open Source Developers

PG's SQL execution plan

J9 digital theory: the Internet across chain bridge has what effect?

7月29-31 | APACHECON ASIA 2022

Fetch 请求不转换BLOB正常显示GBK编码的数据

idea 配置resin

Parse the commonly used methods in the List interface that are overridden by subclasses

Detailed explanation of common examples of dynamic programming
随机推荐
Triacetin是什么化学材料
Detailed explanation of common examples of dynamic programming
太魔人招新啦|快来加入我们吧!
ShapeableImageView 的使用,告别shape、三方库
Fiddle设置接口数据用指定工具查看;Sublime Text设置json数据格式化转换
MySQL安装(详细,适合小白)
【Psychology · Characters】Issue 1
对话亚洲高校首个博士论文奖-裘捷中丨KDD2022
所谓武功再高也怕菜刀-分区、分库、分表和分布式的优劣
日志框架学习
Five data structures of Redis and their corresponding usage scenarios
软件测试分类
如何ES源码中添加一个自己的API 流程梳理
我用这一招让团队的开发效率提升了 100%!
谷歌竞价机器学习如何去理解?
Thread线程类基本使用(上)
腾讯云孟凡杰:我所经历的云原生降本增效最佳实践案例
【LeetCode】118. 杨辉三角 - Go 语言题解
基于 outline 实现头像剪裁以及预览
golang刷leetcode 经典(12) 完全二叉树插入器