windows下 利用 dns 解析IP下载 github 文件
# 定义公共 DNS 服务器列表
$Global:DnsServers = @("1.1.1.1", "8.8.8.8", "9.9.9.9", "223.5.5.5")
function Get-FastestIP {
param([string]$HostName)
Write-Host "正在为 [$HostName] 寻找最优 IP..." -ForegroundColor Cyan
$ipList = New-Object System.Collections.Generic.HashSet[string]
# 并行DNS查询
$dnsJobs = @()
foreach ($dns in $Global:DnsServers) {
$dnsJobs += Start-Job -ScriptBlock {
param($HostName, $DnsServer)
try {
$results = Resolve-DnsName -Name $HostName -Server $DnsServer -Type A -ErrorAction SilentlyContinue
if ($results) {
return $results | Where-Object { $_.IPAddress } | Select-Object -ExpandProperty IPAddress
}
} catch {
return $null
}
} -ArgumentList $HostName, $dns
}
# 等待所有DNS查询完成
$timeoutSeconds = 5
$completedJobs = Wait-Job -Job $dnsJobs -Timeout $timeoutSeconds
# 收集所有IP地址
foreach ($job in $completedJobs) {
$ips = Receive-Job -Job $job
if ($ips) {
foreach ($ip in $ips) {
[void]$ipList.Add($ip)
}
}
}
# 清理作业
Remove-Job -Job $dnsJobs -Force
# 如果公共 DNS 失败,尝试本地 DNS
if ($ipList.Count -eq 0) {
try {
$results = Resolve-DnsName -Name $HostName -Type A -ErrorAction SilentlyContinue
foreach ($res in $results) { if ($res.IPAddress) { [void]$ipList.Add($res.IPAddress) } }
} catch {}
}
if ($ipList.Count -eq 0) { throw "无法解析域名: $HostName" }
Write-Host "找到候选 IP: $($ipList -join ', ')" -ForegroundColor Gray
# 并行测速
$pingJobs = @()
foreach ($ip in $ipList) {
$pingJobs += Start-Job -ScriptBlock {
param($IpAddress)
try {
$tcpClient = New-Object System.Net.Sockets.TcpClient
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
# 尝试连接443端口(HTTPS)
$result = $tcpClient.BeginConnect($IpAddress, 443, $null, $null)
$wait = $result.AsyncWaitHandle.WaitOne(1000, $false) # 1秒超时
if ($wait) {
$latency = $stopwatch.ElapsedMilliseconds
$tcpClient.EndConnect($result)
$tcpClient.Close()
$stopwatch.Stop()
return @{ IP = $IpAddress; Latency = $latency }
} else {
$tcpClient.Close()
$stopwatch.Stop()
return $null
}
} catch {
return $null
}
} -ArgumentList $ip
}
# 等待所有测速完成
$pingResults = @()
foreach ($job in $pingJobs) {
$result = Receive-Job -Job $job -Wait
if ($result) {
$pingResults += $result
}
}
# 清理作业
Remove-Job -Job $pingJobs -Force
# 选择最快的IP
$bestIp = $null
$minPing = [int]::MaxValue
if ($pingResults.Count -gt 0) {
$pingResults = $pingResults | Sort-Object -Property Latency
$bestIp = $pingResults[0].IP
$minPing = $pingResults[0].Latency
Write-Host "选定最优 IP: $bestIp (延迟: ${minPing}ms)" -ForegroundColor Green
} else {
$bestIp = $ipList | Select-Object -First 1
Write-Warning "无法连接任何IP,随机选择: $bestIp"
}
return $bestIp
}
# Invoke-GitHubSmartDownload
function Invoke-GitHubSmartDownload {
<#
.SYNOPSIS
全自动动态测速下载 GitHub 资源 (修复版)
#>
param(
[Parameter(Mandatory=$true)]
[string]$Url,
[string]$OutFile
)
$SessionIpCache = @{}
# 全局忽略证书错误
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 -bor [System.Net.SecurityProtocolType]::Tls11 -bor [System.Net.SecurityProtocolType]::Tls
# === 主逻辑 ===
$currentUrl = $Url
$maxRedirects = 10
$count = 0
while ($count -lt $maxRedirects) {
Write-Host "`n[$count] 请求: $currentUrl" -ForegroundColor White
$uri = [Uri]$currentUrl
$hostName = $uri.Host
if (-not $SessionIpCache.ContainsKey($hostName)) {
$SessionIpCache[$hostName] = Get-FastestIP -HostName $hostName
}
$targetIp = $SessionIpCache[$hostName]
try {
# 创建请求对象
$webRequest = [System.Net.HttpWebRequest]::Create($currentUrl)
$webRequest.Method = "HEAD"
$webRequest.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
$webRequest.AllowAutoRedirect = $false
$webRequest.Timeout = 15000
# 设置Host属性而不是添加Host头
$webRequest.Host = $hostName
$response = $webRequest.GetResponse()
} catch [System.Net.WebException] {
$response = $_.Exception.Response
if (-not $response) {
Write-Error "请求失败: $($_.Exception.Message)"
return
}
}
$statusCode = [int]$response.StatusCode
$headers = $response.Headers
# 处理重定向 (300-399)
if ($statusCode -ge 300 -and $statusCode -lt 400) {
$newUrl = $headers["Location"]
if ([string]::IsNullOrEmpty($newUrl)) {
Write-Error "重定向失败:服务器返回了 $statusCode 但没有 Location 头"
$response.Close()
return
}
# 处理相对路径
if (-not ([Uri]$newUrl).IsAbsoluteUri) {
$baseUri = [Uri]$currentUrl
$newUrl = (new-object Uri($baseUri, $newUrl)).AbsoluteUri
}
$currentUrl = $newUrl
$count++
Write-Host " -> 重定向 ($statusCode) 到: $newUrl" -ForegroundColor Yellow
$response.Close()
continue
}
# 准备下载 (200 OK)
if ($statusCode -eq 200) {
$response.Close()
if (-not $OutFile) {
if ($headers["Content-Disposition"] -match 'filename="?([^"]+)"?') {
$OutFile = $matches[1]
} else {
$OutFile = [IO.Path]::GetFileName(([Uri]$currentUrl).LocalPath)
}
if (-not $OutFile) { $OutFile = "download.bin" }
}
$OutFile = [IO.Path]::GetFullPath($OutFile)
Write-Host "开始下载内容到: $OutFile" -ForegroundColor Cyan
# 修复:使用curl.exe而不是Invoke-WebRequest,更可靠
if (Get-Command "curl.exe" -ErrorAction SilentlyContinue) {
Write-Host "使用curl下载..." -ForegroundColor Gray
$curlArgs = @(
"-L", # 跟随重定向
"--resolve", "$($hostName):443:$($targetIp)",
"-k", # 忽略证书错误
"-o", "`"$OutFile`"",
"-#", # 显示进度条
"`"$currentUrl`""
)
& curl.exe $curlArgs
if ($LASTEXITCODE -eq 0) {
Write-Host "下载完成!" -ForegroundColor Green
return
} else {
Write-Error "curl下载失败,退出码: $LASTEXITCODE"
}
}
# 备用方案:使用WebClient
Write-Host "使用WebClient下载..." -ForegroundColor Gray
try {
$webClient = New-Object System.Net.WebClient
$webClient.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
# 设置代理(如果需要)
# $webClient.Proxy = [System.Net.WebRequest]::GetSystemWebProxy()
# $webClient.Proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials
$webClient.DownloadFile($currentUrl, $OutFile)
Write-Host "下载完成!" -ForegroundColor Green
return
} catch {
Write-Error "WebClient下载失败: $($_.Exception.Message)"
}
# 最后备用方案:Invoke-WebRequest
Write-Host "使用Invoke-WebRequest下载..." -ForegroundColor Gray
try {
$params = @{
Uri = $currentUrl
OutFile = $OutFile
UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
TimeoutSec = 300
}
if ([System.Environment]::Version.Major -ge 7) {
$params["SkipCertificateCheck"] = $true
}
Invoke-WebRequest @params
Write-Host "下载完成!" -ForegroundColor Green
return
} catch {
Write-Error "所有下载方法均失败: $($_.Exception.Message)"
}
}
Write-Error "请求结束,状态码: $statusCode"
if ($response) { $response.Close() }
return
}
}
Invoke-GitHubSmartDownload https://github.com/MoonshotAI/kimi-cli/releases/download/0.75/kimi-0.75-x86_64-pc-windows-msvc.zip
浙公网安备 33010602011771号