V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
NGINX
NGINX Trac
3rd Party Modules
Security Advisories
CHANGES
OpenResty
ngx_lua
Tengine
在线学习资源
NGINX 开发从入门到精通
NGINX Modules
ngx_echo
ysz1121
V2EX  ›  NGINX

openResty IP 数据库

  •  
  •   ysz1121 · 2016-10-22 17:13:09 +08:00 · 4251 次点击
    这是一个创建于 2972 天前的主题,其中的信息可能已经有所发展或是发生改变。

    openResty IP 数据库

    ipip.net IP 数据库之 openresty 版,为了方便 nginx 使用 ip 数据所封装的拓展包。

    使用方式

    本脚本封装了 ipip.net 的主要接口配制好后就可以直接使用,并不需要再去复杂的内部实现。

    需要注意的是如果使用 api 访问需要 http 拓展包。

    代码我已提交至 GitHub: https://github.com/icowan/lua-resty-17mon

    如果对 lua 不了解请看我前段时间写的: 《 Lua 基础学习方式 (一天学会) 》

    如果还没安装 openresty 请看: 《优雅的安装 openresty 》

    `

    nginx 配制

    要使用首先得载入自己写义的 lualib ,这个根据你安装的或使用方式去修改路径。

    lua_package_path "/usr/local/openresty/lualib/?.lua;/var/www/lua-resty-17mon/lualib/?.lua;;";
    lua_package_cpath "/usr/local/openresty/lualib/?.so;;";
    
    error_log /var/www/lua-resty-17mon/logs/lua-resty-17mon.debug.log debug;
    
    server {
        listen 8080;
        server_name localhost;
        charset utf-8;
        location /ipLocation {
            resolver 8.8.8.8; # 如果要使用 api 的话 需要 dns 这可以改成中国的会快一些
            default_type "text/plain";
            content_by_lua_file "/var/www/lua-resty-17mon/script/ip_location.lua";
        }
    }
    
    

    lua 脚本使用

    -- /var/www/lua-resty-17mon/script/ip_location.lua
    
    ngx.req.read_body()
    ngx.header.content_type = "application/json;charset=UTF-8"
    
    local cjson = require "cjson"
    
    local success = function(con)
        return cjson.encode({
            success = true,
            body = con
        })
    end
    
    local failure = function(err)
        return cjson.encode({
            success = false,
            errors = err
        })
    end
    
    -- 参数获取
    local request_args = ngx.req.get_uri_args()
    local ip_address = request_args['ip']
    
    -- 如果不需要验证可以不用此拓展
    local checkIp = require("ip_check"):new(ip_address)
    
    -- 验证 ip
    local ok, err = checkIp:checkIp()
    if not ok then
        ngx.say(failure(err))
        return
    end
    
    -- 使用本地数据库
    local ipdetail, err = require("ip_location"):new(ip_address, "/var/www/lua-resty-17mon/file/17monipdb.dat")
    if not ipdetail then
        ngx.log(ngx.ERR, err)
        ngx.say(failure(err))
        return
    end
    
    local ipLocation, err = ipdetail:location()
    if not ipLocation then
        ngx.log(ngx.ERR, err)
        ngx.say(failure(err))
        return
    end
    
    ngx.say(success(ipLocation))
    
    

    通过免费 api 获取 ip 信息

    如果通过 api 获取数据需要使用 http 服务,这里需要使用lua-resty-http 这里我已经把它直接放到lualib/resty目录了,可以直接使用 感谢pintsized提供的脚本

    -- /var/www/lua-resty-17mon/script/ip_location.lua
    
    local ipdetail, err = require("ip_location"):new(ip_address)
    if not ipdetail then
        ngx.log(ngx.ERR, err)
        ngx.say(failure(err))
        return
    end
    
    local ipLocation, err = ipdetail:locationApiFree()
    if not ipLocation then
        ngx.log(ngx.ERR, err)
        ngx.say(failure(err))
        return
    end
    
    ngx.say(success(ipLocation))
    
    

    通过付费 api 获取 ip 信息

    -- /var/www/lua-resty-17mon/script/ip_location.lua
    
    local ipdetail, err = require("ip_location"):new(ip_address, "", "your token")
    if not ipdetail then
        ngx.log(ngx.ERR, err)
        ngx.say(failure(err))
        return
    end
    
    local ipLocation, err = ipdetail:locationApiFree()
    if not ipLocation then
        ngx.log(ngx.ERR, err)
        ngx.say(failure(err))
        return
    end
    
    ngx.say(success(ipLocation))
    
    

    获取 aip 使用状态

    -- /var/www/lua-resty-17mon/script/ip_location.lua
    
    local ipdetail, err = require("ip_location"):new(ip_address, "your token")
    if not ipdetail then
        ngx.log(ngx.ERR, err)
        ngx.say(failure(err))
        return
    end
    
    local ipLocation, err = ipdetail:apiStatus()
    if not ipLocation then
        ngx.log(ngx.ERR, err)
        ngx.say(failure(err))
        return
    end
    
    ngx.say(success(ipLocation))
    
    

    返回数据结构

    Response

    返回类型: JSON

    | 参数 | 类型 | 备注 | | --- | --- | --- | | success | bool | true or false | | errors or body | string | 当 success 为 false 时 errors 有值否则返回 body |

    body 返回参数详情

    | 参数 | 类型 | 备注 | | --- | --- | --- | | country | string | 国家 | | city | string | 省会或直辖市(国内) | | region | string | 地区或城市 (国内) | | place | string | 学校或单位 (国内) | | operator | string | 运营商字段 | | latitude | string | 纬度 | | longitude | string | 经度 | | timeZone | string | 时区一, 可能不存在 | | timeZoneCode | string | 时区码 | | administrativeAreaCode | string | 中国行政区划代码 | | internationalPhoneCode | string | 国际电话代码 | | countryTwoDigitCode | string | 国家二位代码 | | worldContinentCode | string | 世界大洲代码 |

    返回结果参考:

    {
    	"success": true,
    	"body": {
    		"country": "",  // 国家
    	    "city": "",  // 省会或直辖市(国内)
    	    "region": "",  // 地区或城市 (国内)
    	    "place": "",  // 学校或单位 (国内)
    	    "operator": "",  // 运营商字段(只有购买了带有运营商版本的数据库才会有)
    	    "latitude": "",  // 纬度     (每日版本提供)
    	    "longitude": "",  // 经度     (每日版本提供)
    	    "timeZone": "",  // 时区一, 可能不存在  (每日版本提供)
    	    "timeZoneCode": "",  // 时区码, 可能不存在  (每日版本提供)
    	    "administrativeAreaCode": "",  // 中国行政区划代码    (每日版本提供)
    	    "internationalPhoneCode": "",  // 国际电话代码        (每日版本提供)
    	    "countryTwoDigitCode": "",  // 国家二位代码        (每日版本提供)
    	    "worldContinentCode": ""  // 世界大洲代码        (每日版本提供)
    	}
    }
    

    ERROR 结果参考

    {
    	"success": false,
    	"erros": "retun messages..."
    }
    

    查询状态结果参考

    {
    	"success": true,
    	"body": {
    		"limit": false, // 是否已受访问限制
           "hour": 99680,  // 一个小时内剩余次数
           "day": 999680,  // 24 小时内剩余次数
    	}
    }
    

    尾巴

    难得为开源社区贡献一份力量,希望有同样需求的同学们可以不用再去写复杂的底层逻辑,应该更多的把时间估计业务流程上。

    同样希望这个脚本能提供给 ipip.net 官方推荐脚本。

    如有任何疑问欢迎联系我: [email protected]

    或访问我 网站: LatteCake

    原文地址: https://lattecake.com/post/20102

    第 1 条附言  ·  2016-10-22 20:51:29 +08:00

    修复一处错误:

    local ipLocation, err = ipdetail:locationApi("your sid", "your uid")
    if not ipLocation then
        ngx.log(ngx.ERR, err)
        ngx.say(failure(err))
        return
    end
    

    负费的应该使用ipdetail:locationApi("your sid", "your uid") 这个方法

    6 条回复    2016-10-23 12:31:44 +08:00
    ivmm
        1
    ivmm  
       2016-10-22 17:15:12 +08:00
    关于 OpenResty 有个疑惑。

    它都是基于 Nginx 主线版本的,如果要用于生产环境那么稳定性如何呢? 还是说生产环境需要自己用 Nginx 安装相关模块?
    ysz1121
        2
    ysz1121  
    OP
       2016-10-22 20:46:15 +08:00
    @ivmm OpenResty 已经把 nginx 的主要模块包含进来了,你可以查看 openresty 包目录里的 nginx 目录。
    ysz1121
        3
    ysz1121  
    OP
       2016-10-22 20:46:54 +08:00
    @ivmm lua 没有多线程,如果有需要可以通过协同处理器来完成,这个我有写过,下次有机会我发出来
    ivmm
        4
    ivmm  
       2016-10-22 21:10:21 +08:00
    @ysz1121 不是,我是说 OpenResty 是基于 Nginx mainline 的版本,而不是 stable 的版本。 生产环境怎么用。 可靠么,而且它 OpenResty 的主线更新还不及时
    cnZary
        5
    cnZary  
       2016-10-23 11:16:12 +08:00
    双标题
    neoblackcap
        6
    neoblackcap  
       2016-10-23 12:31:44 +08:00
    @ivmm cloudflare 在生产环境里面都是用 OpenRestry ,还是挺可靠的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2217 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 15:52 · PVG 23:52 · LAX 07:52 · JFK 10:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.