Files
wish-pool/app/test/ip-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

200 lines
7.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

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 } from 'react'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
import { Alert, AlertDescription } from '@/components/ui/alert'
import { Globe, ExternalLink, Info, CheckCircle, AlertCircle } from 'lucide-react'
export default function IpTestPage() {
const [externalIp, setExternalIp] = useState<string | null>(null)
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const fetchExternalIp = async () => {
setLoading(true)
setError(null)
try {
const response = await fetch('https://api.ipify.org?format=json')
if (!response.ok) {
throw new Error('無法獲取外部IP')
}
const data = await response.json()
setExternalIp(data.ip)
} catch (error) {
console.error('Error fetching external IP:', error)
setError('無法獲取外部IP地址')
} finally {
setLoading(false)
}
}
return (
<div className="container mx-auto p-6 max-w-4xl space-y-6">
<div className="text-center">
<h1 className="text-3xl font-bold mb-2">IP </h1>
<p className="text-muted-foreground">IP地址</p>
</div>
{/* 說明 */}
<Alert>
<Info className="h-4 w-4" />
<AlertDescription>
<div className="font-medium mb-2"> 127.0.0.1</div>
<div className="text-sm space-y-1">
<div> </div>
<div> </div>
<div> IP檢測會更準確</div>
<div> 使IP</div>
</div>
</AlertDescription>
</Alert>
{/* 外部IP檢測 */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Globe className="w-5 h-5" />
IP檢測
</CardTitle>
<CardDescription>
IP地址
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex items-center gap-4">
<Button
onClick={fetchExternalIp}
disabled={loading}
className="flex items-center gap-2"
>
<ExternalLink className="w-4 h-4" />
{loading ? '檢測中...' : '檢測真實IP'}
</Button>
{externalIp && (
<div className="flex items-center gap-2">
<span className="font-medium">IP:</span>
<Badge variant="default" className="flex items-center gap-1">
<CheckCircle className="w-3 h-3" />
{externalIp}
</Badge>
</div>
)}
</div>
{error && (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
<div className="text-sm text-muted-foreground">
<p>IP地址就是你的真實公網IP</p>
<ul className="list-disc list-inside mt-2 space-y-1">
<li>IP白名單</li>
<li>IP檢測功能</li>
<li></li>
</ul>
</div>
</CardContent>
</Card>
{/* 測試方法 */}
<Card>
<CardHeader>
<CardTitle>IP的方法</CardTitle>
<CardDescription>IP檢測功能的方法</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-3">
<div>
<h4 className="font-medium mb-2">1. 使 ngrok </h4>
<div className="text-sm text-muted-foreground space-y-1">
<p> ngrok: <code className="bg-muted px-1 rounded">npm install -g ngrok</code></p>
<p> : <code className="bg-muted px-1 rounded">ngrok http 3000</code></p>
<p> 使 ngrok URL訪問你的應用</p>
<p> IP檢測功能</p>
</div>
</div>
<div>
<h4 className="font-medium mb-2">2. </h4>
<div className="text-sm text-muted-foreground space-y-1">
<p> VercelNetlify </p>
<p> IP檢測會更準確</p>
<p> IP白名單功能</p>
</div>
</div>
<div>
<h4 className="font-medium mb-2">3. 使</h4>
<div className="text-sm text-muted-foreground space-y-1">
<p> Nginx Apache </p>
<p> IP </p>
<p> IP檢測</p>
</div>
</div>
</div>
</CardContent>
</Card>
{/* 配置建議 */}
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div>
<h4 className="font-medium mb-2"></h4>
<div className="text-sm text-muted-foreground">
<p> <code className="bg-muted px-1 rounded">.env.local</code> </p>
<pre className="bg-muted p-2 rounded mt-2 text-xs">
{`# 禁用IP白名單檢查
ENABLE_IP_WHITELIST=false
# 或者允許本地IP
ALLOWED_IPS=127.0.0.1,192.168.1.0/24`}
</pre>
</div>
</div>
<div>
<h4 className="font-medium mb-2"></h4>
<div className="text-sm text-muted-foreground">
<p></p>
<pre className="bg-muted p-2 rounded mt-2 text-xs">
{`# 啟用IP白名單
ENABLE_IP_WHITELIST=true
# 設置允許的IP地址
ALLOWED_IPS=你的真實IP地址,其他允許的IP`}
</pre>
</div>
</div>
</div>
</CardContent>
</Card>
{/* 快速連結 */}
<div className="flex justify-center gap-4">
<Button variant="outline" onClick={() => window.open('/test/ip-debug', '_blank')}>
<Globe className="w-4 h-4 mr-2" />
IP調試
</Button>
<Button variant="outline" onClick={() => window.open('/test/ip-format-test', '_blank')}>
<CheckCircle className="w-4 h-4 mr-2" />
IPv4格式測試
</Button>
<Button variant="outline" onClick={() => window.open('/api/ip', '_blank')}>
<ExternalLink className="w-4 h-4 mr-2" />
IP API
</Button>
</div>
</div>
)
}