Files
wish-pool/app/test/ip-format-test/page.tsx
aken1023 2808852e9f Fix IPv4 display and IP detection logic
Improved IP detection and display logic to always show IPv4 format, converting IPv6-mapped IPv4 addresses (e.g., ::ffff:127.0.0.1) and IPv6 loopback (::1) to 127.0.0.1. Updated API endpoint, display components, and added dedicated test/debug pages for IP format and detection. Added documentation summarizing the fixes and new features.
2025-08-01 15:35:15 +08:00

246 lines
8.4 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client'
import { useState, useEffect } from 'react'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Alert, AlertDescription } from '@/components/ui/alert'
import { Globe, RefreshCw, CheckCircle, AlertCircle, Info } from 'lucide-react'
interface IpTestResult {
originalIp: string
cleanedIp: string
isIPv4: boolean
isIPv6: boolean
isLocalhost: boolean
description: string
}
export default function IpFormatTestPage() {
const [testResults, setTestResults] = useState<IpTestResult[]>([])
const [loading, setLoading] = useState(false)
// 測試IP地址清理函數
function cleanIpForDisplay(ip: string): string {
if (!ip) return '127.0.0.1';
// 移除空白字符
ip = ip.trim();
// 處理IPv6格式的IPv4地址 (例如: ::ffff:192.168.1.1)
if (ip.startsWith('::ffff:')) {
return ip.substring(7);
}
// 處理純IPv6本地回環地址
if (ip === '::1') {
return '127.0.0.1';
}
// 驗證是否為有效的IPv4地址
const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
if (ipv4Regex.test(ip)) {
return ip;
}
// 如果不是有效的IPv4返回默認值
return '127.0.0.1';
}
// 檢查IP類型
function analyzeIp(ip: string): { isIPv4: boolean; isIPv6: boolean; isLocalhost: boolean; description: string } {
const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
const ipv6Regex = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
const isIPv4 = ipv4Regex.test(ip);
const isIPv6 = ipv6Regex.test(ip) || ip.startsWith('::ffff:') || ip === '::1';
const isLocalhost = ip === '127.0.0.1' || ip === '::1' || ip === 'localhost';
let description = '';
if (ip.startsWith('::ffff:')) {
description = 'IPv6格式的IPv4地址';
} else if (ip === '::1') {
description = 'IPv6本地回環地址';
} else if (isIPv4) {
description = '標準IPv4地址';
} else if (isIPv6) {
description = 'IPv6地址';
} else {
description = '無效的IP地址格式';
}
return { isIPv4, isIPv6, isLocalhost, description };
}
const runTests = () => {
setLoading(true);
const testIps = [
'::ffff:127.0.0.1',
'::1',
'127.0.0.1',
'192.168.1.1',
'::ffff:192.168.1.100',
'2001:db8::1',
'invalid-ip',
'localhost',
'::ffff:203.0.113.1',
'10.0.0.1'
];
const results: IpTestResult[] = testIps.map(originalIp => {
const cleanedIp = cleanIpForDisplay(originalIp);
const analysis = analyzeIp(originalIp);
return {
originalIp,
cleanedIp,
...analysis
};
});
setTestResults(results);
setLoading(false);
};
useEffect(() => {
runTests();
}, []);
return (
<div className="container mx-auto p-6 max-w-6xl space-y-6">
<div className="text-center">
<h1 className="text-3xl font-bold mb-2">IPv4 </h1>
<p className="text-muted-foreground">IP地址清理和IPv4格式轉換功能</p>
</div>
{/* 說明 */}
<Alert>
<Info className="h-4 w-4" />
<AlertDescription>
<div className="font-medium mb-2"></div>
<div className="text-sm space-y-1">
<div> IPv6格式的IPv4地址能正確轉換為IPv4</div>
<div> IP地址都顯示為標準IPv4格式</div>
<div> IP地址格式的處理邏輯</div>
<div> </div>
</div>
</AlertDescription>
</Alert>
{/* 測試結果 */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Globe className="w-5 h-5" />
IP格式轉換測試結果
</CardTitle>
<CardDescription>
IP地址格式的清理和轉換結果
</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
{testResults.map((result, index) => (
<div key={index} className="border rounded-lg p-4 space-y-2">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<span className="font-medium">IP:</span>
<Badge variant="outline" className="font-mono">
{result.originalIp}
</Badge>
</div>
<div className="flex items-center gap-2">
<span className="font-medium">:</span>
<Badge variant="default" className="font-mono">
{result.cleanedIp}
</Badge>
</div>
</div>
<div className="flex items-center gap-4 text-sm">
<div className="flex items-center gap-1">
{result.isIPv4 ? (
<CheckCircle className="w-4 h-4 text-green-500" />
) : (
<AlertCircle className="w-4 h-4 text-red-500" />
)}
<span>IPv4: {result.isIPv4 ? '是' : '否'}</span>
</div>
<div className="flex items-center gap-1">
{result.isIPv6 ? (
<CheckCircle className="w-4 h-4 text-blue-500" />
) : (
<span className="text-gray-400">-</span>
)}
<span>IPv6: {result.isIPv6 ? '是' : '否'}</span>
</div>
<div className="flex items-center gap-1">
{result.isLocalhost ? (
<CheckCircle className="w-4 h-4 text-orange-500" />
) : (
<span className="text-gray-400">-</span>
)}
<span>: {result.isLocalhost ? '是' : '否'}</span>
</div>
</div>
<div className="text-sm text-muted-foreground">
{result.description}
</div>
</div>
))}
</div>
</CardContent>
</Card>
{/* 操作按鈕 */}
<div className="flex justify-center">
<Button onClick={runTests} disabled={loading} className="flex items-center gap-2">
<RefreshCw className={`w-4 h-4 ${loading ? 'animate-spin' : ''}`} />
{loading ? '測試中...' : '重新測試'}
</Button>
</div>
{/* 總結 */}
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription>
IPv4格式轉換的關鍵點
</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-3">
<div>
<h4 className="font-medium mb-2"> </h4>
<ul className="text-sm space-y-1 text-muted-foreground">
<li> <code>::ffff:127.0.0.1</code> <code>127.0.0.1</code></li>
<li> <code>::1</code> <code>127.0.0.1</code></li>
<li> <code>127.0.0.1</code> <code>127.0.0.1</code> ()</li>
<li> <code>192.168.1.1</code> <code>192.168.1.1</code> ()</li>
</ul>
</div>
<div>
<h4 className="font-medium mb-2"> </h4>
<ul className="text-sm space-y-1 text-muted-foreground">
<li> IP地址 <code>127.0.0.1</code> ()</li>
<li> null <code>127.0.0.1</code> ()</li>
</ul>
</div>
<div>
<h4 className="font-medium mb-2">🎯 </h4>
<p className="text-sm text-muted-foreground">
IP地址都是標準的IPv4格式
</p>
</div>
</div>
</CardContent>
</Card>
</div>
)
}