前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >golang源码分析之geoip2-golang

golang源码分析之geoip2-golang

作者头像
golangLeetcode
发布2022-08-02 19:26:22
7270
发布2022-08-02 19:26:22
举报
文章被收录于专栏:golang算法架构leetcode技术php

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数据。下面,我们看下这个包应该如何使用:

代码语言:javascript
复制
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这个包的源码。它的源码很简单只有一个文件:

代码语言:javascript
复制
reader.go

调用了maxminddb数据解析包github.com/oschwald/maxminddb-golang来做 数据的解析,仅仅做了一层接口上的封装,和对应地理数据格式(企业、城市、国家、AnonymousIP、Domain、ISP)的定义。

比如城市信息:

代码语言:javascript
复制
// 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函数

代码语言:javascript
复制
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

代码语言:javascript
复制
type Reader struct {
  mmdbReader   *maxminddb.Reader
  databaseType databaseType
}

Reader上定义了City,County等函数

代码语言:javascript
复制
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做了简单的封装。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-09-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 golang算法架构leetcode技术php 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云服务器
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档