LOGO 首页 OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 技术文档 其他文档  
 
网站管理员

开源API离线库 ip2region.xdb 的 ASP 版解码函数,输入 IP 返回所在国家省市县运营商

admin
2026年10月14日 10:12 本文热度 123

先说明:ip2region xdb 官方没有原生 ASP(VBScript)版本,帖子 http://41332.oa22.cn 是别人移植的 xdb 二进制解析逻辑,下面给你直接可用的 经典 ASP (VBScript) 解码函数,适配 ip2region.xdb,输入 IP,返回【国家 省 市 县】合并单行字符串。 

⚠️ 重要限制:

  1. ​ASP 是单线程、VBS 没有原生大文件随机读的高效方案,下面这个版本采用 服务端预加载 xdb 到内存字节数组(适合中小站点,xdb 约 10MB 左右);如果并发很高、IIS 内存紧张,建议改成二进制流按需读取版本。

  2. 编码:ip2region 返回内容是 UTF-8,ASP 默认是 GB2312,内置 UTF8→GB 转码,防止乱码。

  3. 文件路径:ip2region.xdb 放在网站根目录,可自行修改 xdbPath。

  4. 依赖:IIS ASP 开启 ADODB.Stream(大部分服务器默认开启)。

<%
'=========================================================
' ip2region.xdb ASP(VBScript) 解析函数
' 函数:GetIpRegion(ip)
' 参数:ip字符串,如 "220.181.xxx.xxx"
' 返回:合并字符串 国家 省 市 区县,无数据返回"未知"
' 适配ip2region xdb 1.x格式(默认的ip2region.xdb)
' 来源参考:oa22.cn/bbs.asp?id=41332 的解析思路移植
'=========================================================
Dim xdbBuf, xdbFileLen, xdbHeader, xdbIndexStart, xdbIndexEnd, xdbDataStart
Dim xdbVectorIndexPtr, xdbVectorIndexLen
Dim xdbIsLoad : xdbIsLoad = False
' 【初始化:加载xdb到内存,全局只加载一次】
Sub LoadXdb()
    Dim stm
    Dim xdbPath
    xdbPath = Server.MapPath("/ip2region.xdb") ' 修改为你的xdb物理路径
    Set stm = Server.CreateObject("ADODB.Stream")
    stm.Mode = 3
    stm.Type = 1
    stm.Open
    stm.LoadFromFile xdbPath
    xdbBuf = stm.Read
    xdbFileLen = LenB(xdbBuf)
    stm.Close
    Set stm = Nothing
    
    ' 读取头部固定信息(ip2region xdb header 36字节)
    If xdbFileLen < 36 Then
        xdbIsLoad = False
        Exit Sub
    End If
    xdbIndexStart = ReadUint4(0)
    xdbIndexEnd = ReadUint4(4)
    xdbVectorIndexPtr = ReadUint4(8)
    xdbVectorIndexLen = ReadUint4(12)
    xdbDataStart = 36
    xdbIsLoad = True
End Sub
' 从字节数组指定偏移读4字节无符号int (Little-Endian)
Function ReadUint4(offset)
    If offset + 4 > xdbFileLen Then
        ReadUint4 = 0
        Exit Function
    End If
    Dim b1,b2,b3,b4
    b1 = AscB(MidB(xdbBuf, offset+1, 1))
    b2 = AscB(MidB(xdbBuf, offset+2, 1))
    b3 = AscB(MidB(xdbBuf, offset+3, 1))
    b4 = AscB(MidB(xdbBuf, offset+4, 1))
    ReadUint4 = b1 + b2*256 + b3*65536 + b4*16777216
End Function
' 从字节数组指定偏移读3字节无符号int (Little-Endian)
Function ReadUint3(offset)
    If offset + 3 > xdbFileLen Then
        ReadUint3 = 0
        Exit Function
    End If
    Dim b1,b2,b3
    b1 = AscB(MidB(xdbBuf, offset+1, 1))
    b2 = AscB(MidB(xdbBuf, offset+2, 1))
    b3 = AscB(MidB(xdbBuf, offset+3, 1))
    ReadUint3 = b1 + b2*256 + b3*65536
End Function
' IP字符串转uint32
Function IpToUint(ipStr)
    Dim arr, i, ret
    arr = Split(ipStr,".")
    If UBound(arr)<>3 Then
        IpToUint = -1
        Exit Function
    End If
    ret = 0
    For i=0 To 3
        Dim v
        v = CInt(arr(i))
        If v<0 Or v>255 Then
            IpToUint = -1
            Exit Function
        End If
        ret = ret * 256 + v
    Next
    IpToUint = ret
End Function
' 二分查找索引
Function BinarySearch(ipUint)
    Dim low, high, mid, ipStart, ipEnd, dataPtr, offset
    low = 0
    high = (xdbIndexEnd - xdbIndexStart)\12 -1
    Do While low <= high
        mid = Int((low + high)/2)
        offset = xdbIndexStart + mid * 12
        ipStart = ReadUint4(offset)
        ipEnd = ReadUint4(offset+4)
        dataPtr = ReadUint3(offset+8)
        If ipUint < ipStart Then
            high = mid -1
        ElseIf ipUint > ipEnd Then
            low = mid +1
        Else
            BinarySearch = dataPtr
            Exit Function
        End If
    Loop
    BinarySearch = 0
End Function
' 读取location字符串(utf8)
Function ReadLocation(ptr)
    If ptr = 0 Or ptr >= xdbFileLen Then
        ReadLocation = ""
        Exit Function
    End If
    Dim p, b, sB
    sB = ""
    p = ptr
    Do
        If p >= xdbFileLen Then Exit Do
        b = AscB(MidB(xdbBuf, p+1,1))
        If b = 0 Then Exit Do
        sB = sB & MidB(xdbBuf, p+1,1)
        p = p +1
    Loop
    ReadLocation = Utf8ToGb2312(sB)
End Function
' UTF8字节串转GB2312(ASP VBS)
Function Utf8ToGb2312(sUtf8)
    Dim stm
    Set stm = Server.CreateObject("ADODB.Stream")
    stm.Type = 2
    stm.Charset = "UTF-8"
    stm.Open
    stm.WriteText sUtf8
    stm.Position = 0
    stm.Type = 1
    Dim bin
    bin = stm.Read
    stm.Close
    stm.Type = 2
    stm.Charset = "GB2312"
    stm.Open
    stm.Write bin
    stm.Position = 0
    Utf8ToGb2312 = stm.ReadText
    stm.Close
    Set stm = Nothing
End Function
' ===================== 对外主函数 =====================
Function GetIpRegion(ipStr)
    If Not xdbIsLoad Then Call LoadXdb()
    If Not xdbIsLoad Then
        GetIpRegion = "未知"
        Exit Function
    End If
    Dim ipUint, dataPtr, loc
    ipUint = IpToUint(ipStr)
    If ipUint = -1 Then
        GetIpRegion = "未知"
        Exit Function
    End If
    dataPtr = BinarySearch(ipUint)
    If dataPtr <= 0 Then
        GetIpRegion = "未知"
        Exit Function
    End If
    loc = ReadLocation(dataPtr)
    ' ip2region原生格式:国家|省|市|区县|运营商,用 | 分割
    Dim arrLoc
    arrLoc = Split(loc,"|")
    Dim res
    res = ""
    If UBound(arrLoc)>=0 Then res = res & Trim(arrLoc(0))
    If UBound(arrLoc)>=1 Then res = res & " " & Trim(arrLoc(1))
    If UBound(arrLoc)>=2 Then res = res & " " & Trim(arrLoc(2))
    If UBound(arrLoc)>=3 Then res = res & " " & Trim(arrLoc(3))
    GetIpRegion = res
End Function
' ============ 测试示例 ============
' Response.Write GetIpRegion("220.181.208.61")
%>

使用方式

<%
Dim ip, addr
ip = Request.ServerVariables("REMOTE_ADDR")
addr = GetIpRegion(ip)
Response.Write "IP地址:" & ip & "<br>"
Response.Write "归属地:" & addr
%>

重要说明

  1. ip2region 默认的 xdb 返回格式是 国家|省份|城市|区县|运营商,代码里只取前四段,空格拼接成一个字段,不单独拆分字段;

  2. 如果想要带上运营商,把拼接那行自己加上 arrLoc(4) 即可;

  3. 这个是 经典 ASP(VBS),不是 .NET,IIS 传统 ASP 站点直接跑;

  4. 报错排查:

    • LoadFromFile 失败:路径错、xdb 文件不存在、IIS 用户没有读权限;

    • 返回一直 “未知”:xdb 版本不对,要用官方标准的 ip2region.xdb,不要用旧的 dat 库;

    • 乱码:UTF8 转码函数依赖 ADODB.Stream,虚拟主机如果禁用这个组件就无法使用。

性能补充

上面代码是二分索引版本(稳定兼容所有标准 xdb)。

下面这个是缓存版,同一个 IP 查过之后存入 Application,减少重复二分查找开销。

'=========================================================

' ip2region.xdb ASP(VBScript) 解析函数 + Application全局缓存版

' 函数:GetIpRegion(ip)

' 参数:ip字符串,如 "220.181.208.61"

' 返回:合并字符串 国家 省 市 区县,无数据返回"未知"

' 参考:oa22.cn/bbs.asp?id=41332

' 缓存说明:使用Application缓存IP结果,设置过期时间,避免无限膨胀

' 注意:Application是应用程序全局缓存,IIS回收后缓存清空

'=========================================================

Dim xdbBuf, xdbFileLen, xdbIndexStart, xdbIndexEnd, xdbDataStart

Dim xdbVectorIndexPtr, xdbVectorIndexLen

Dim xdbIsLoad : xdbIsLoad = False

Const CACHE_KEY_PREFIX = "ipreg_"

Const CACHE_EXPIRE_SEC = 1800 '缓存30分钟,可自行调整,单位秒


' 【初始化:加载xdb到内存,全局只加载一次】

Sub LoadXdb()

    Dim stm

    Dim xdbPath

    xdbPath = Server.MapPath("/ip2region.xdb") '修改xdb路径

    Set stm = Server.CreateObject("ADODB.Stream")

    stm.Mode = 3

    stm.Type = 1

    stm.Open

    stm.LoadFromFile xdbPath

    xdbBuf = stm.Read

    xdbFileLen = LenB(xdbBuf)

    stm.Close

    Set stm = Nothing

    

    If xdbFileLen < 36 Then

        xdbIsLoad = False

        Exit Sub

    End If

    xdbIndexStart = ReadUint4(0)

    xdbIndexEnd = ReadUint4(4)

    xdbVectorIndexPtr = ReadUint4(8)

    xdbVectorIndexLen = ReadUint4(12)

    xdbDataStart = 36

    xdbIsLoad = True

End Sub


' 从字节数组指定偏移读4字节无符号int (Little-Endian)

Function ReadUint4(offset)

    If offset + 4 > xdbFileLen Then

        ReadUint4 = 0

        Exit Function

    End If

    Dim b1,b2,b3,b4

    b1 = AscB(MidB(xdbBuf, offset+1, 1))

    b2 = AscB(MidB(xdbBuf, offset+2, 1))

    b3 = AscB(MidB(xdbBuf, offset+3, 1))

    b4 = AscB(MidB(xdbBuf, offset+4, 1))

    ReadUint4 = b1 + b2*256 + b3*65536 + b4*16777216

End Function


' 从字节数组指定偏移读3字节无符号int (Little-Endian)

Function ReadUint3(offset)

    If offset + 3 > xdbFileLen Then

        ReadUint3 = 0

        Exit Function

    End If

    Dim b1,b2,b3

    b1 = AscB(MidB(xdbBuf, offset+1, 1))

    b2 = AscB(MidB(xdbBuf, offset+2, 1))

    b3 = AscB(MidB(xdbBuf, offset+3, 1))

    ReadUint3 = b1 + b2*256 + b3*65536

End Function


' IP字符串转uint32

Function IpToUint(ipStr)

    Dim arr, i, ret

    arr = Split(ipStr,".")

    If UBound(arr)<>3 Then

        IpToUint = -1

        Exit Function

    End If

    ret = 0

    For i=0 To 3

        Dim v

        v = CInt(arr(i))

        If v<0 Or v>255 Then

            IpToUint = -1

            Exit Function

        End If

        ret = ret * 256 + v

    Next

    IpToUint = ret

End Function


' 二分查找索引

Function BinarySearch(ipUint)

    Dim low, high, mid, ipStart, ipEnd, dataPtr, offset

    low = 0

    high = (xdbIndexEnd - xdbIndexStart)\12 -1

    Do While low <= high

        mid = Int((low + high)/2)

        offset = xdbIndexStart + mid * 12

        ipStart = ReadUint4(offset)

        ipEnd = ReadUint4(offset+4)

        dataPtr = ReadUint3(offset+8)

        If ipUint < ipStart Then

            high = mid -1

        ElseIf ipUint > ipEnd Then

            low = mid +1

        Else

            BinarySearch = dataPtr

            Exit Function

        End If

    Loop

    BinarySearch = 0

End Function


' 读取location字符串(utf8)

Function ReadLocation(ptr)

    If ptr = 0 Or ptr >= xdbFileLen Then

        ReadLocation = ""

        Exit Function

    End If

    Dim p, b, sB

    sB = ""

    p = ptr

    Do

        If p >= xdbFileLen Then Exit Do

        b = AscB(MidB(xdbBuf, p+1,1))

        If b = 0 Then Exit Do

        sB = sB & MidB(xdbBuf, p+1,1)

        p = p +1

    Loop

    ReadLocation = Utf8ToGb2312(sB)

End Function


' UTF8字节串转GB2312(ASP VBS)

Function Utf8ToGb2312(sUtf8)

    Dim stm

    Set stm = Server.CreateObject("ADODB.Stream")

    stm.Type = 2

    stm.Charset = "UTF-8"

    stm.Open

    stm.WriteText sUtf8

    stm.Position = 0

    stm.Type = 1

    Dim bin

    bin = stm.Read

    stm.Close

    stm.Type = 2

    stm.Charset = "GB2312"

    stm.Open

    stm.Write bin

    stm.Position = 0

    Utf8ToGb2312 = stm.ReadText

    stm.Close

    Set stm = Nothing

End Function


' 内部:直接查询xdb,不经过缓存

Function RawQueryIp(ipStr)

    If Not xdbIsLoad Then Call LoadXdb()

    If Not xdbIsLoad Then

        RawQueryIp = "未知"

        Exit Function

    End If

    Dim ipUint, dataPtr, loc

    ipUint = IpToUint(ipStr)

    If ipUint = -1 Then

        RawQueryIp = "未知"

        Exit Function

    End If

    dataPtr = BinarySearch(ipUint)

    If dataPtr <= 0 Then

        RawQueryIp = "未知"

        Exit Function

    End If

    loc = ReadLocation(dataPtr)

    Dim arrLoc

    arrLoc = Split(loc,"|")

    Dim res

    res = ""

    If UBound(arrLoc)>=0 Then res = res & Trim(arrLoc(0))

    If UBound(arrLoc)>=1 Then res = res & " " & Trim(arrLoc(1))

    If UBound(arrLoc)>=2 Then res = res & " " & Trim(arrLoc(2))

    If UBound(arrLoc)>=3 Then res = res & " " & Trim(arrLoc(3))

    RawQueryIp = res

End Function


' ===================== 对外主函数(带Application缓存+锁) =====================

Function GetIpRegion(ipStr)

    Dim cacheKey, cacheVal, cacheInfo, nowSec

    cacheKey = CACHE_KEY_PREFIX & Replace(ipStr,".","_")

    nowSec = DateDiff("s", "1970-01-01", Now())

    

    Application.Lock

    On Error Resume Next

    cacheInfo = Application(cacheKey)

    On Error GoTo 0

    

    '缓存存在并且没过期,直接返回

    If cacheInfo <> "" Then

        Dim expSec, retStr

        expSec = Split(cacheInfo,"|")(0)

        retStr = Split(cacheInfo,"|")(1)

        If nowSec < CLng(expSec) Then

            Application.UnLock

            GetIpRegion = retStr

            Exit Function

        Else

            '过期,删掉旧缓存

            Application(cacheKey) = Empty

        End If

    End If

    Application.UnLock

    

    '缓存缺失/过期,真实查询xdb

    Dim result

    result = RawQueryIp(ipStr)

    

    '写入缓存:过期时间|结果文本

    Dim saveInfo

    saveInfo = CStr(nowSec + CACHE_EXPIRE_SEC) & "|" & result

    Application.Lock

    Application(cacheKey) = saveInfo

    Application.UnLock

    

    GetIpRegion = result

End Function


' ============ 辅助:清空全部IP缓存,后台可以调用 ============

Sub ClearIpRegionCache()

    Dim key

    Application.Lock

    For Each key In Application.Contents

        If Left(key, Len(CACHE_KEY_PREFIX)) = CACHE_KEY_PREFIX Then

            Application.Contents.Remove(key)

        End If

    Next

    Application.UnLock

End Sub


' ============ 测试示例 ============

'Response.Write GetIpRegion("220.181.208.61")

关键优化点说明

  1. Application.Lock / UnLock读写 Application 加锁,防止并发同时写同一个缓存 key 引发冲突、数据错乱,经典 ASP 标准写法。

  2. 缓存结构 过期时间戳|归属地字符串不是永久缓存,默认 30 分钟(CACHE_EXPIRE_SEC = 1800),你可以改成 600(10 分钟)、3600(1 小时)。

  3. IP 里.替换成_: Application 的 key 不能直接带.,所以做替换处理,避免异常。

  4. 分离 RawQueryIp 和 GetIpRegionRawQueryIp 是裸查 xdb 逻辑,方便你有时候想强制不读缓存、直接查库时调用。

  5. 配套清理子程序 ClearIpRegionCache()放在后台管理页面,一键清空所有 IP 缓存,比如更新 xdb 文件后手动清缓存:

<% Call ClearIpRegionCache() %>​

注意事项(ASP Application 固有局限)

  • Application 缓存是IIS 进程级:应用池回收、站点重启、IIS 重启,缓存全部清空,xdb 内存缓冲区也会重新加载。

  • 高并发站点,如果 IP 访问非常离散,缓存 key 会持续增多,占内存;如果发现内存上涨明显:

    • 缩短 CACHE_EXPIRE_SEC 过期时间

    • 或者改用 Session/Cookie 缓存(不推荐,每个用户独立),或者自建文本 / Access 缓存方案

  • xdb 文件本身还是一次性加载到全局内存,和上一版一致,查询速度快。


该文章在 2026/10/14 10:12:16 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved  粤ICP备13012886号-1  粤公网安备44030602007207号