WuYongJie f646b71813
Some checks failed
CI Check / check (push) Has been cancelled
chore: 初始化本地仓库并同步最近改动
2025-11-18 17:50:16 +08:00

107 lines
3.0 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.

import { NextRequest, NextResponse } from 'next/server'
/**
* 判断IP是否为内网地址
*/
function isIntranetIP(ip: string): boolean {
if (!ip) return false
// 处理可能存在的端口号
const cleanIP = ip.split(':')[0]
// localhost
if (cleanIP === '127.0.0.1' || cleanIP === 'localhost' || cleanIP === '::1') {
return true
}
// IPv4 内网IP段判断
const ipv4Regex = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/
const match = cleanIP.match(ipv4Regex)
if (match) {
const [, a, b, c, d] = match.map(Number)
// 验证IP有效性
if (a > 255 || b > 255 || c > 255 || d > 255) {
return false
}
// 10.0.0.0 - 10.255.255.255 (Class A)
if (a === 10) return true
// 172.16.0.0 - 172.31.255.255 (Class B)
if (a === 172 && b >= 16 && b <= 31) return true
// 192.168.0.0 - 192.168.255.255 (Class C)
if (a === 192 && b === 168) return true
// 169.254.0.0 - 169.254.255.255 (Link-local)
if (a === 169 && b === 254) return true
}
return false
}
/**
* 获取客户端真实IP地址
*/
function getClientIP(request: NextRequest): string {
// 优先级:x-real-ip > x-forwarded-for > connection
const xRealIP = request.headers.get('x-real-ip')
if (xRealIP) return xRealIP
const xForwardedFor = request.headers.get('x-forwarded-for')
if (xForwardedFor) {
// x-forwarded-for 可能包含多个IP,取第一个(客户端真实IP)
return xForwardedFor.split(',')[0].trim()
}
const cfConnectingIP = request.headers.get('cf-connecting-ip') // Cloudflare
if (cfConnectingIP) return cfConnectingIP
const trueClientIP = request.headers.get('true-client-ip') // Akamai
if (trueClientIP) return trueClientIP
// 如果都没有,返回默认值
return 'unknown'
}
/**
* GET /api/network-status
* 返回用户的网络环境状态
*/
export async function GET(request: NextRequest) {
try {
const clientIP = getClientIP(request)
const isIntranet = isIntranetIP(clientIP)
// 获取当前访问的域名
const hostname = request.headers.get('host') || ''
const publicDomains = (process.env.PUBLIC_DOMAINS || '').split(',').map(s => s.trim()).filter(Boolean)
const isPublicDomain = publicDomains.length > 0 ? publicDomains.includes(hostname) : false
console.log(`[Network Status] IP: ${clientIP}, isIntranet: ${isIntranet}, hostname: ${hostname}`)
return NextResponse.json({
success: true,
isIntranet,
isPublicDomain,
// 不返回完整IP地址(隐私保护)
ipMasked: clientIP.split('.').slice(0, 2).join('.') + '.xxx.xxx',
message: isIntranet
? '检测到内网访问'
: '检测到公网访问',
intranetUrl: isIntranet && isPublicDomain
? (process.env.NEXT_PUBLIC_INTRANET_URL || '')
: null
})
} catch (error) {
console.error('[Network Status] Error:', error)
return NextResponse.json({
success: false,
error: '网络状态检测失败'
}, { status: 500 })
}
}