首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

ASP.NET (C#) 實作 WHOIS 域名查詢系統完整教學

     編輯:關於C語言

WHOIS 協議簡介

WHOIS (RFC 3912) 是基於 TCP 埠 43 的純文字查詢協議。客戶端連線至 WHOIS 伺服器,發送域名 + \r\n,伺服器回傳註冊資訊後關閉連線。各頂級域 (TLD) 有各自的權威 WHOIS 伺服器。

ASP.NET Web Forms 完整實作 (.aspx)

前端頁面 (WhoisQuery.aspx)


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WhoisQuery.aspx.cs" Inherits="Demo.WhoisQuery" %>



    域名 WHOIS 查詢
    


    

WHOIS 域名查詢


後端程式碼 (WhoisQuery.aspx.cs)


using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.UI;

namespace Demo
{
    public partial class WhoisQuery : Page
    {
        // 常見 TLD 對應的 WHOIS 伺服器
        private static readonly Dictionary WhoisServers = new(StringComparer.OrdinalIgnoreCase)
        {
            { "com", "whois.verisign-grs.com" },
            { "net", "whois.verisign-grs.com" },
            { "org", "whois.pir.org" },
            { "info", "whois.afilias.net" },
            { "biz", "whois.biz" },
            { "tw", "whois.twnic.net.tw" },
            { "cn", "whois.cnnic.cn" },
            { "jp", "whois.jprs.jp" },
            { "kr", "whois.kr" },
            { "hk", "whois.hkirc.hk" },
            { "io", "whois.nic.io" },
            { "ai", "whois.nic.ai" },
            { "dev", "whois.nic.google" },
            { "app", "whois.nic.google" },
        };

        protected void Page_Load(object sender, EventArgs e) { }

        protected void btnQuery_Click(object sender, EventArgs e)
        {
            lblError.Visible = false;
            litResult.Text = "";

            string domain = txtDomain.Text.Trim().ToLowerInvariant();
            if (string.IsNullOrEmpty(domain))
            {
                ShowError("請輸入域名");
                return;
            }

            // 簡單驗證域名格式
            if (!Regex.IsMatch(domain, @"^[a-z0-9.-]+\.[a-z]{2,}$"))
            {
                ShowError("域名格式不正確");
                return;
            }

            try
            {
                string server = GetWhoisServer(domain);
                string result = QueryWhois(server, domain);
                litResult.Text = Server.HtmlEncode(result); // 防 XSS
            }
            catch (Exception ex)
            {
                ShowError($"查詢失敗:{ex.Message}");
                // 實務上記錄完整堆疊追蹤
            }
        }

        private string GetWhoisServer(string domain)
        {
            // 取得 TLD (最後一段)
            string tld = domain.Split('.').Last();
            
            if (WhoisServers.TryGetValue(tld, out string server))
                return server;

            // 兩字元 TLD 通常歸 RIPE NCC (歐洲)
            if (tld.Length == 2)
                return "whois.ripe.net";

            // 預設回落
            return "whois.iana.org"; // IANA 根伺服器會轉介
        }

        private string QueryWhois(string server, string domain)
        {
            using (var client = new TcpClient())
            {
                client.ReceiveTimeout = 10000;
                client.SendTimeout = 10000;
                client.Connect(server, 43); // WHOIS 標準埠

                using (var stream = client.GetStream())
                using (var writer = new StreamWriter(stream, Encoding.ASCII) { AutoFlush = true })
                using (var reader = new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: false))
                {
                    // 發送查詢指令
                    writer.WriteLine(domain);

                    // 讀取完整回應 (伺服器關閉連線時結束)
                    return reader.ReadToEnd();
                }
            }
        }

        private void ShowError(string message)
        {
            lblError.Text = message;
            lblError.Visible = true;
        }
    }
}

核心技術點解析

1. WHOIS 伺服器選擇策略

  • 硬編碼對照表:常見 TLD 直接指定權威伺服器,速度最快
  • IANA 根伺服器:whois.iana.org 可查詢任何 TLD 的權威伺服器位址 (參考回應中的 refer: 欄位)
  • 遞迴查詢:先問 IANA 取得權威伺服器,再連線查詢細節 (兩次連線)

2. 編碼處理

  • 請求:ASCII (標準要求)
  • 回應:UTF-8 (現代伺服器多支援),但舊伺服器可能用 ISO-8859-1 或 Big5 (中文 TLD)
  • 建議:Encoding.UTF8 讀取,失敗時嘗試 Encoding.GetEncoding("iso-8859-1")

3. 非同步改良 (ASP.NET 4.5+ / Core)


private async Task QueryWhoisAsync(string server, string domain)
{
    using (var client = new TcpClient())
    {
        await client.ConnectAsync(server, 43);
        using (var stream = client.GetStream())
        using (var writer = new StreamWriter(stream, Encoding.ASCII) { AutoFlush = true })
        using (var reader = new StreamReader(stream, Encoding.UTF8))
        {
            await writer.WriteLineAsync(domain);
            return await reader.ReadToEndAsync();
        }
    }
}

// 按鈕事件改為 async void (Web Forms) 或 async Task (MVC/Core)
protected async void btnQuery_Click(object sender, EventArgs e)
{
    // ... 驗證 ...
    string result = await QueryWhoisAsync(server, domain);
    litResult.Text = Server.HtmlEncode(result);
}

4. 快取策略 (減少重複查詢、避免被 Ban)


// 簡單記憶體快取 (生產環境建議 Redis/MemoryCache)
private static readonly MemoryCache WhoisCache = MemoryCache.Default;

private string GetCachedOrQuery(string domain)
{
    string cacheKey = $"whois_{domain}";
    if (WhoisCache.Contains(cacheKey))
        return (string)WhoisCache.Get(cacheKey);

    string result = QueryWhois(GetWhoisServer(domain), domain);
    
    // 快取 1 小時 (WHOIS 資料不常變動)
    WhoisCache.Set(cacheKey, result, DateTimeOffset.Now.AddHours(1));
    return result;
}

5. 回應解析結構化 (進階)


public class WhoisRecord
{
    public string DomainName { get; set; }
    public string Registrar { get; set; }
    public DateTime? CreationDate { get; set; }
    public DateTime? ExpiryDate { get; set; }
    public string NameServers { get; set; }
    public string Status { get; set; }
    public string RawText { get; set; }
}

public WhoisRecord ParseWhois(string raw)
{
    var record = new WhoisRecord { RawText = raw };
    // 使用 Regex 擷取關鍵欄位 (各伺服器格式略有不同)
    record.DomainName = Extract(raw, @"Domain Name:\s*(.+)");
    record.Registrar = Extract(raw, @"Registrar:\s*(.+)");
    // ... 其他欄位
    return record;
}

private string Extract(string text, string pattern)
{
    var m = Regex.Match(text, pattern, RegexOptions.IgnoreCase);
    return m.Success ? m.Groups[1].Value.Trim() : null;
}

常見問題與解決方案

問題原因解決
連線逾時伺服器回應慢/防火牆阻擋輸出 43 埠增加逾時、檢查伺服器防火牆/雲端安全群組
回應亂碼編碼不符 (中文 TLD 常見)嘗試多種編碼讀取、或保留原始位元組讓前端處理
查無資料 / 格式異常伺服器回應格式變更/限制頻率加入快取、降低查詢頻率、支援多伺服器輪詢
被 IP 封鎖短時間大量查詢快取、速率限制、使用代理池、申請商業 API

現代替代方案

  1. RDAP (Registration Data Access Protocol):WHOIS 繼任者,REST + JSON 格式,標準化、支援國際化、可驗證簽章
  2. 第三方 API:WhoisXML API, DomainTools, ICANN Lookup — 付費但穩定、結構化、含歷史資料
  3. whois 命令列工具:Linux/Windows 內建,適合伺服器端腳本整合

結語

WHOIS 查詢雖屬經典協議,但在域名監控、品牌保護、網路資產管理仍不可或缺。掌握 TCP 43 埠通訊、編碼處理、伺服器選擇策略與快取機制,即可建立穩健的查詢系統。現代專案建議優先評估 RDAP 或商業 API,降低維護成本並獲得更豐富的結構化資料。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved