Ruby gem geoip and Rack::GeoIPCountry

wikipedia上对于geolocation的解释是这样的:

Geolocation is the identification of the real-world geographic location of an Internet-connected computer, mobile device, website visitor or other.

检测的方法貌似也有很多:

Geolocation can be performed by associating a geographic location with the Internet Protocol (IP) address, MAC address, RFID, hardware embedded article/production number, embedded software number (such as UUID, Exif/IPTC/XMP or modern steganography), invoice, Wi-Fi connection location, or device GPS coordinates, or other, perhaps self-disclosed information.

(班门弄斧一下先,呵呵呵呵)

ruby里面取到geo信息的一个相对方便的办法是使用rubygem geoip,虽然本质上还是使用maxmind的data,但是免去了编译和安装其c library的麻烦。

安装gem并下载其depend到的geoip database:

$ sudo gem install geoip
$ wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz && gunzip GeoIP.dat.gz

如果想要城市信息,还可以下载稍微大一点的带city info的free database:

$ wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz && gunzip GeoLiteCity.dat.gz

简单的测试一下:

require 'rubygems'
require 'geoip'

p GeoIP.new('GeoIP.dat').country("google.com")
p GeoIP.new('GeoLiteCity.dat').city("baidu.com")

alright, looks good:

["google.com", "66.249.91.104", 225, "US", "USA", "United States", "NA"]
["baidu.com", "220.181.6.81", "CN", "CHN", "China", "AS", "22", "Beijing", "", 39.9289, 116.3883]

由于geo的普遍性,把其做成可以plug&play的Rack middleware绝对是个好主意,这就是接下来要介绍的Rack::GeoIPCountryCodeRack Contest的first place。

其原理就是调用geoip gem获得访问IP的geo信息并写入request header,这样后面的app或者middleware就能读到并处理了。

同样写个简单的middleware测试一下:

require 'geo_ip_country'

class GeoTest
  def initialize(app)
    @app = app
  end
 
  def call(env)
    puts "Remote Address: #{env['REMOTE_ADDR']}"
    puts "GeoIP Country ID: #{env['X_GEOIP_COUNTRY_ID']}"
    puts "GeoIP Country Code: #{env['X_GEOIP_COUNTRY_CODE']}"
    puts "GeoIP Country Code3: #{env['X_GEOIP_COUNTRY_CODE3']}"
    puts "GeoIP Country: #{env['X_GEOIP_COUNTRY']}"
    puts "GeoIP Continent: #{env['X_GEOIP_CONTINENT']}"
    @app.call(env)
  end
end

use Rack::ContentLength
use Rack::GeoIPCountry
use GeoTest

run Proc.new { |env| [200, { 'Content-Type' => 'text/html' }, 'OK'] }

rackup起来后,访问http://localhost:9292,确认console下输出了我们想要的geo信息:

Remote Address: 127.0.0.1
GeoIP Country ID: 0
GeoIP Country Code: --
GeoIP Country Code3: --
GeoIP Country: N/A
GeoIP Continent: --
127.0.0.1 - - [25/Feb/2010 16:36:11] "GET / HTTP/1.1" 200 2 0.0016

当然上面的127.0.0.1是不会有任何信息的,local network也是不会在database里面找到对应的,只有当真正的外网ip hit到我们的server时,我们才能看到有意义的geo信息。

Related posts:

2 Comments on "Ruby gem geoip and Rack::GeoIPCountry"

  1. Sunng China Mozilla SeaMonkey Windows says:

    汗,我以为走错了。。。
    纳爱斯~

Got something to say? Go for it!

使用新浪微博登陆