news 2026/10/8 16:15:45

WHOIS域名信息查询源码解析:从43端口到结构化数据

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
WHOIS域名信息查询源码解析:从43端口到结构化数据

简介:这是一套面向网站开发者与运维人员的域名WHOIS信息查询源码,基于PHP实现,可部署于自有服务器,用于实时查询域名注册商、到期时间、域名服务器等核心注册信息,弥补第三方平台在定制化查询体验上的局限。压缩包共包含19个文件,整体大小约290KB,以PHP业务逻辑文件为核心,配合HTML页面结构、CSS样式、JS交互以及woff/ttf/eot/svg字体与png/gif/ico图标素材,覆盖从查询入口到结果展示的完整链路,目录划分清晰,便于直接修改部署。代码同时包含logo、404页面等细节,适合作为学习PHP表单处理、API请求与结果渲染的参考样例。已有278人浏览学习,对于需要快速搭建WHOIS查询工具或了解域名信息查询实现原理的开发者而言,这套轻量源码具有直接的参考价值。

1. 域名信息查询同款WHOIS源码:这套打包好的代码到底能拿来做什么

拿到一个名为“域名信息查询同款WHOIS源码.zip”的压缩包,第一反应别急着解压。先想清楚:WHOIS 本身不是什么新鲜技术,它是一个运行了三十多年的查询协议,所有域名注册商、备案查询站、安全分析平台背后都在用同一套底层的查询-响应机制。所谓“同款源码”,拆开看通常就是三类东西的组合——连接 WHOIS 服务器的客户端、解析各国注册局返回文本的规则表、以及一个让人能输入域名就看到注册人、到期时间、状态码的查询页面。它能不能用、值不值得投入,取决于你拿到的是哪类源码,以及你打算把它放在什么场景里跑。这篇笔记我会把原理讲透,再按最常见的工程结构,从零把一套可用的 WHOIS 查询服务搭出来,并把解析、缓存、避坑这些真正决定项目生死的细节一次说清。

2. 搞清楚 WHOIS 查询到底查了什么:协议、端口与服务器分配

2.1 WHOIS 不是 Web 接口,是 43 端口上的纯文本对话

很多第一次接触的人会误以为 WHOIS 查询是调某个 HTTP API,实际上传统 WHOIS 走的是 TCP 43 端口,客户端连上服务器后发送一行域名文本,服务器直接把结果以纯文本形式吐回来,然后断开连接。这个流程在 RFC 3912 里定义得很简单:请求就是一行 ASCII 字符串加回车换行,响应是一段没有统一格式的文本。所有“域名信息查询”工具的本质,都是把这段不可控的文本解析成结构化的字段。

用 Python 写一个最小查询客户端不超过十行,核心就是 socket 连接加收发数据:

import socket def whois_lookup(domain: str, server: str = "whois.verisign-grs.com", port: int = 43) -> str: # 创建 TCP 连接,WHOIS 协议默认端口是 43 with socket.create_connection((server, port), timeout=10) as sock: # 按协议要求,发送域名加换行,编码必须是 ASCII sock.sendall((domain + "\r\n").encode("ascii")) buf = [] while True: # 循环收数据,直到服务器关闭连接为止 chunk = sock.recv(4096) if not chunk: break buf.append(chunk.decode("iso-8859-1", errors="replace")) return "".join(buf) if __name__ == "__main__": print(whois_lookup("example.com"))

这段代码的逻辑很直白:建立连接、按协议发送查询行、循环收取直到对方断开。这里有个容易被忽略的参数——decode("iso-8859-1"),WHOIS 响应的历史包袱很重,很多海外注册局返回的内容在纯 ASCII 之外还带 Latin-1 字符,用 UTF-8 解码很可能直接抛异常。实际项目中我会把解码方式也做成可配置项,因为你没法预测上游服务器今天用哪种编码。

2.2 域名和 IP 的 WHOIS 服务器不是同一套:查谁得先知道该问谁

“同款源码”里最核心的隐藏逻辑就是服务器选择。域名注册数据分散在不同注册局手里,每个注册局有自己的 WHOIS 服务器,而且注册局之间的数据还会往下游批发商分发。比如.com和.net的权威数据在 Verisign,.org在 PIR,.cn在 CNNIC,欧洲的.eu在 EURid。IP 地址段则归五个区域互联网注册机构管——ARIN 管北美、RIPE 管欧洲、APNIC 管亚太,你要查一个 IP 归属,得先从 IANA 的 whois.iana.org 问出该 IP 属于哪个 RIR,再转向对应的服务器。

常见的做法是在源码里维护一张“后缀到服务器”的映射表,查不到时再走 IANA 自动跳转。表格接在下面:

查询对象默认 WHOIS 服务器说明
.com / .netwhois.verisign-grs.comVerisign 运营,数据不含隐私字段
.orgwhois.pir.orgPublic Interest Registry
.cnwhois.cnnic.cnCNNIC 中文域名与 .cn 域名
IP 地址段whois.iana.org 起跳先查 RIR 归属再转查
.iowhois.nic.ioIdentity Digital 运营

需要特别提醒的是,即使查询的是 .com,也不一定能从 Verisign 直接拿到完整注册人信息。很多注册商对 WHOIS 输出做了隐私保护替换,返回结果里可能只有“REDACTED FOR PRIVACY”这类占位符。源码里如果只有单一服务器地址,不做上游递归或备选切换,那查询质量就会打折。

2.3 命令行先跑通再动代码:用系统自带工具验证网络链路的连通性

在接进自己代码之前,先用系统自带的 whois 命令验证目标服务器通不通。很多部署环境根本装不上 whois 客户端,或者 43 端口被安全组挡着,这些问题在命令行阶段暴露出来,比在源码里排查快得多。

# Linux/macOS 下直接查 example.org,看系统带的工具能否拿到原始返回 whois example.org | head -50 # 如果没装,用 apt 安装(Debian/Ubuntu),装的是 jwhois 或 whois 包 sudo apt-get install whois # 用 curl 也能模拟 WHOIS 请求,这是最轻量的拨测方法 curl -s --max-time 10 telnet://whois.verisign-grs.com:43 <<< "example.com"

上面三条命令是三层排查思路:第一条验证本机有没有客户端,第二条解决安装问题,第三条绕开系统客户端直接用 curl 模拟协议。如果第三条能返回结果而代码跑不通,说明源码里 socket 收发逻辑有问题;如果第三条也超时,那就是网络层的问题——检查安全组是否放行 43 端口,以及本机防火墙出方向策略。这个排错顺序能替你省下一大半无意义的代码调试时间。

3. 把源码跑起来:工程结构与三个必调参数

3.1 一个典型的 WHOIS 源码包结构拆解

解压“同款源码.zip”后你会看到几个常见目录,不管它用的是 PHP 还是 Python,骨架基本一致:

  • 入口脚本(index.php / main.py / app.js):负责接收域名输入、调用查询模块、把结果渲染成页面。
  • 连接模块(whois_client.py / whois.php):封装 socket 或 fsockopen 逻辑,负责连接服务器、收发数据、处理超时。
  • 解析规则目录(parsers/):里面按注册局放了一堆正则或规则文件,这是整个包里最值钱的部分。
  • 缓存层(cache/ 或 Redis 配置):用于减少重复查询、降低被封号风险。
  • 前端模板(templates/):查询表单和结果展示页面。

拿到源码我建议按这个顺序做三件事:先把入口脚本连到数据库的地方注释掉,看纯查询能不能跑;再检查连接模块里的服务器映射表是否完整;最后看解析规则文件是否带默认兜底规则(因为 WHOIS 返回格式不统一,缺兜底规则就意味着随时解析失败)。任何“同款源码”如果这三样不全,跑起来的质量都不会高。

3.2 最小可用部署:本地起一个纯查询脚本

定位到源码包里负责查询的核心函数,先绕开 Web 框架直接跑命令行版本,这样能把网络、协议、解析三者隔离出来单独验证。以 Python 为例,修改过的最小验证脚本是这样的:

import json import sys from whois_client import WHOISClient # 假设这是包里的连接模块 from parsers import get_parser # 这是解析规则加载器 def query_and_parse(domain: str) -> dict: # 初始化客户端,参数依次是超时、重试次数、缓存开关 client = WHOISClient(timeout=10, retries=2, use_cache=False) raw_text = client.lookup(domain) if not raw_text: return {"error": "empty response"} # 根据域名后缀选择合适的解析器,找不到就用默认兜底解析器 tld = domain.rsplit(".", 1)[-1] parser = get_parser(tld) or get_parser("_default") return parser.parse(raw_text) if __name__ == "__main__": domain = sys.argv[1] if len(sys.argv) > 1 else "example.com" print(json.dumps(query_and_parse(domain), ensure_ascii=False, indent=2))

要注意这里的get_parser(tld)是典型的规则分发表:它对 .com、.cn、.org 各返回一个专用解析器,谁都不匹配时走_default。专用解析器里的是带锚点、考虑过多行的正则在提取;而默认解析器通常只是粗暴地按冒号切分。这两个参数——timeout和retries——是部署环境里最先要调的。本地网络通畅时 10 秒超时足够,但上游部分注册局响应极慢,尤其是在跨境网络环境下,建议超时放宽到 20 秒;重试次数不要大于 2 次,否则大量无效请求会让你的出口 IP 很快被临时限速。

3.3 接进 Web 页面前,先把返回结果做一次“人工核验”

把源码接到网页之前,建议先对同几个域名做一次人肉比对。所谓人肉比对,就是打开命令行 whois 工具查询一次原始输出,再和源码解析出来的字段逐项对照。这一步能发现多个问题:解析规则匹配不到导致的字段缺失、把注册商名称错配到注册人字段、状态码被正则吃掉一半等等。

我在实际项目里吃过一次大亏:某个 .cn 域名的解析规则对“Domain Status: ok”这种行只配了半条正则,导致状态字段只匹配出o而不是ok,前端页面直接显示“域名状态异常”。这种问题光看单元测试根本暴露不出来,因为模拟样本里没覆盖这一行格式。所以凡是涉及 WHOIS 解析的源码,第一课就是:不要相信任何一条拿真实域名跑不出正确结果的解析规则。

4. 解析 WHOIS 返回文本:正则之外,还需要一张规则表

4.1 为什么不能只靠正则:注册局之间的格式差异远超想象

WHOIS 协议没规定响应内容的格式,这是所有“域名信息查询源码”最痛的点。Verisign 返回的 .com 记录里有“Registrar: GoDaddy.com, LLC”和“Registry Expiry Date: 2026-08-15T04:00:00Z”;CNNIC 返回的 .cn 记录格式完全不同,字段名是“注册商”和“过期时间”,中文和英文混着来。某些欧洲注册局返回的字段名是首字母大写的“Registrant Name”,另一些是大小写敏感的“registrant_name”。

拿正则去覆盖每一种格式是不现实的,所以工程上的做法是分三层:按 TLD 找解析器、按解析器内定义的关键字段正则去匹配、最后对完全匹配不上的字段做启发式猜测或留空。源码里真正值钱的部分不是连接逻辑(那是几十行的事),而是那张覆盖了数百个后缀的规则表。规则表不是一次性写出来的,是靠一条条真实返回样本喂出来的。

我封装过一个简化的解析器,核心是用正则加显式兜底逻辑:

import re class GenericWhoisParser: def __init__(self): # 规则表:字段名 -> 正则表达式 self.field_patterns = { "registrar": re.compile(r"Registrar:\s*(.+)"), "expiry_date": re.compile(r"Registry Expiry Date:\s*(.+)"), "creation_date": re.compile(r"Creation Date:\s*(.+)"), "status": re.compile(r"Domain Status:\s*(.+)"), } self._default_pattern = re.compile(r"^\s*([^:]+):\s*(.+)$") def parse(self, raw_text: str) -> dict: result = {} for line in raw_text.splitlines(): matched = False # 逐条规则尝试匹配,命中即写入 for field, pattern in self.field_patterns.items(): m = pattern.search(line) if m: result[field] = m.group(1).strip() matched = True break if not matched: # 兜底规则:按冒号切分,存入 raw 字段 m = self._default_pattern.match(line) if m and m.group(2).strip(): result.setdefault("raw_fields", {})[m.group(1).strip()] = m.group(2).strip() return result

这段代码里的参数关键点有两个:field_patterns里正则的贪婪和锚点选择。(.+)能捕获行尾所有内容,但如果注册局在同一字段上返回多行(比如多个 Domain Status),这种单行匹配就会漏掉后面几行。遇到过多个状态的域名时,需要把search改成findall并把 result 存成列表。兜底逻辑保证了未知格式的字段至少不会丢,会出现在raw_fields里供后续人工分析,而不是直接被静默丢弃——这个设计是从生产环境里沉淀出来的血泪经验。

4.2 解析后的数据结构:分字段存还是存原始文本,决定你后面能不能查

很多“同款源码”只做了解析展示,没做数据落库。这导致同一个域名查第二次又得全量走网络,效率极低。我建议在源码基础上加一个缓存表,至少存三个关键字段:域名、到期时间、原始返回文本。结构参考下面:

列名类型用途
domainvarchar(255) 主键查询主键,确保同一域名只存一条
registrarvarchar(255)注册商,用于展示
expiry_datedatetime到期时间,用于过期提醒
raw_textmediumtext原始返回,解析器升级后可重放
updated_attimestamp最后查询时间,控制刷新频率

将原始文本也存下来非常关键:当解析规则出 Bug 时,不需要重新发起网络查询,直接从库里捞raw_text回放就能验证新正则。没有这个字段,每次调试都要打一次上游,既慢又容易被限速。

4.3 隐私保护字段:拿不到真实注册人信息时怎么展示不误导用户

近年各大注册局和注册商普遍启用 WHOIS 隐私保护,返回结果里真实注册人信息被替换成代理邮箱或占位符。源码解析完如果发现 Registrant Name 是 “REDACTED FOR PRIVACY” 或 “DATA NOT DISCLOSED”,前端要明确展示“该域名开启隐私保护”,而不是让用户以为注册人就叫“REDACTED”。

做这条消息过滤时不要用简单的等值判断,因为各注册商的占位符文案五花八门:有全大写的、有带下划线的、还有PrivacyGuard.org之类的代理名称。稳妥做法是维护一个隐私标识词表,命中就标记privacy_protected=true。这也是解析模块里少数容易写但又极其影响结果可信度的逻辑之一。

5. 域名信息查询的五个常见坑:从连不通到解析错,逐一排查

5.1 端口 43 被安全组拦截,客户端一直超时

现象:本地命令行能查出结果,一上服务器就超时,或机房部署后永远报错“连接失败”。

原因:当前机器的安全组出站规则禁了非 80/443 端口。43 端口不在常规放行列表里,云厂商默认安全组大概率不放行。

解决:在云控制台安全组出站方向放行 TCP 43 端口,目标地址写 0.0.0.0/0(WHOIS 服务器分散在全球各地,无法按 IP 白名单限制)。改完等 30 秒生效,再用 curl 拨测一次复验。

5.2 上游 WHOIS 服务器限速,查询一多就报 429 或返回空

现象:连查几十个域名后,所有请求开始超时或返回一条错误信息。多数注册局有频率限制策略,检测到一段时间内来自同一 IP 的密集查询,会静默丢弃请求或直接断开连接。

原因:客户端没做查询频率控制,或者缓存失效太快导致重复查询打到上游。

解决:一是在连接模块里加最小请求间隔,同一个 IP 每秒最多发一两个查询;二是把 Redis 或数据库缓存时长设为 24 小时以上(域名注册信息不是实时变化的,几小时级的延迟完全不影响用户体验)。

5.3 .cn 返回的中文注册商信息被错误解码成乱码

现象:解析 .cn 域名时,注册商和联系人显示成注册商一类乱码。

原因:CNNIC 的 WHOIS 返回是 GBK/GB2312 编码,源码里统一按 Latin-1 或 UTF-8 解码,必然错乱。

解决:在连接模块里按服务器域名区分解码方式——连接 whois.cnnic.cn 时用gb18030解码,其他服务器用iso-8859-1。判断方式别硬编码,建议把编码格式直接做成服务器映射表里的一列,后续遇到其他非 ASCII 注册局只用加表,不用改代码。

5.4 一批域名全解析成 None,但原始返回里有字段

现象:解析结果全是空值,把raw_text拉出来看字段其实都在。

原因:解析规则的正则写得太严,比如要求Creation Date:冒号后必须有一个空格,而实际上某些注册局返回的是制表符或多个空格。

解决:把解析正则改成更宽容的写法,例如Creation Date:\s*而不是Creation Date:。同时在解析完跑一遍自检:如果expiry_date为空,但raw_fields里存在疑似日期的值,触发告警日志。生产环境里我会把这个告警接进错误监控,它比单元测试更能反映真实数据质量。

5.5 查询的是子域名,拿到的却是注册局默认错误页

现象:用户输入www.example.com查 WHOIS,返回的结果是“Domain not found”。

原因:WHOIS 协议查询只支持主域名,服务器不识别www前缀。源码里没有对输入做归一化处理,直接把整串域名发给了上游。

解决:在入口处做域名提取逻辑——从输入里剥掉www.以及可能的子域名前缀。注意不能简单用split(".")[-2:],因为.com.cn、.org.uk这类多段后缀会导致误切。正确做法是拿一份公共后缀列表(类似 publicsuffix.org 的规则)做最长匹配,提取出真正的主域名。这个坑看着小,实际却是用户投诉最多的问题之一。

6. 验证与进阶:用真实数据做回归测试,再给查询服务加一层监控

源码跑通只是第一步,真正要投入生产环境前,你得有自己的验证手段。我的习惯是建立一个固定域名样本集,每个样本都标注了期望解析结果,跑任何修改后都必须通过这批样本:

域名期望解析结果特殊关注点
example.comregistrar 非空、状态含 ok常规场
隐私保护域名(如任意一个开启保护的 .com)privacy_protected=true占位符识别
中文域名(xn--开头的 punycode 形式)不报错、能找到注册局编码与 IDN 处理
不存在的域名(如 nonexistent-xyz-12345.com)错误信息可读错误分支处理

把这批用例放进命令行跑一遍,比对解析 JSON 的差异,比启动 Web 页面点按钮高效得多。只有这批样本全部通过后,我才会接回 Web 页面做手动确认。

监控方面,我会在源码里加两个指标:查询成功率和解析成功率。前者看网络链路,后者看规则质量。任何低于 99% 的情况都值得立刻查日志——解析成功率掉到 95% 以下,通常意味着某家注册局改版了返回格式,你的正则规则需要更新了。WHOIS 解析是一个长尾问题,永远有新后缀、新格式、新隐私策略冒出来,代码稳定运行三个月后还会给你“惊喜”。所以,从第一天起就把raw_text落库、把解析失败样本单独留一份、把异常告警接出来,是我这些年做域名信息查询方向最值得推荐的习惯。你踩过的每一个非标准格式,都会成为下一版规则表的注脚。希望这些经验能帮你在第一批域名解析失败时,少走两趟弯路。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/8 16:15:17

OpenCode Token监控插件:实时追踪Token用量、缓存命中率与TPS

1. 为什么我要给 OpenCode 写一个 Token 监控插件用 OpenCode 写代码这件事&#xff0c;一旦上手就很难回去了。它把终端、编辑器、模型调用串成一条顺滑的链路&#xff0c;敲几行指令就能让模型帮你改文件、跑测试、补注释。但用得越久&#xff0c;我心里越没底——我根本不知…

作者头像 李华
网站建设 2026/10/8 16:13:32

UE实战进阶:从蓝图到C++的Gameplay框架与渲染管线工程化指南

1. 从零拆解UE实战&#xff1a;为什么“引擎会用”和“引擎用得好”是两回事很多人第一次打开Unreal Engine&#xff0c;是被它那套“所见即所得”的编辑器吸引的。拖一个立方体进去&#xff0c;加个材质&#xff0c;放个光源&#xff0c;点一下播放&#xff0c;画面就出来了。…

作者头像 李华
网站建设 2026/10/8 16:13:31

UE实战进阶:Gameplay框架、C++与蓝图边界及渲染管线优化

1. 从"能跑蓝图"到"看懂引擎"&#xff1a;为什么第五篇要聊实战与高级主题 很多人学UE&#xff08;Unreal Engine&#xff09;的路径都差不多&#xff1a;先跟着教程拖几个Actor&#xff0c;连一堆蓝图节点&#xff0c;做出个能跑能跳的小人&#xff0c;然…

作者头像 李华
网站建设 2026/10/8 16:13:15

Coding Agent 执行记录与 AgentLoop 审计:提示词注入风险与监控实践

1. 从执行记录切入&#xff1a;Coding Agent 到底在做什么 Coding Agent 这个词最近半年被聊得很多&#xff0c;但大部分讨论都停留在“它能帮我写代码”这个层面。我一开始也是这么理解的&#xff0c;直到有一次排查一个线上问题&#xff0c;翻看 Agent 的执行记录时才发现&am…

作者头像 李华
网站建设 2026/10/8 16:12:45

AI编程助手skills实战:从原理到落地,提升开发效率

1. 从“skills”这个热词说起&#xff1a;它到底在解决什么问题最近半年&#xff0c;不管是在技术群还是各种开发者社区&#xff0c;“skills”这个词出现的频率高得离谱。你随便翻一下热搜词列表就能看到&#xff1a;skills、claude code、codex、plugin、agents、find skills…

作者头像 李华
网站建设 2026/10/8 16:11:21

WorkBuddy 实战指南:从 Skill 配置到跨行业工作台搭建

最近在技术社群里&#xff0c;越来越多人在晒 WorkBuddy 的玩法。有人拿它清理陈年老代码&#xff0c;有人拿它搭运营数据看板&#xff0c;还有老师用它生成了课堂互动小程序的完整 demo。这个工具在很长一段时间里都被当成“AI 编程助手”看待&#xff0c;但实际用下来&#x…

作者头像 李华