暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

golang源码分析之geoip2-golang

        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做了简单的封装。


              文章转载自golang算法架构leetcode技术php,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

              评论