fix: 更新 DownloadFile 函数以使用 fasthttp 客户端,优化下载性能并简化错误处理逻辑
This commit is contained in:
64
util/url.go
64
util/url.go
@@ -2,16 +2,16 @@ package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
// GetImageExtension 根据文件头检测图片格式并返回对应的扩展名
|
||||
@@ -66,60 +66,44 @@ func normalizeURL(rawURL string) string {
|
||||
|
||||
// DownloadFile 下载文件到指定目录,返回带有正确扩展名的完整文件路径
|
||||
func DownloadFile(urlStr string, dirPath string) (filepath string, err error) {
|
||||
// 解析URL获取域名
|
||||
parsedURL, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("URL解析失败: %v", err)
|
||||
// 创建fasthttp客户端
|
||||
client := &fasthttp.Client{
|
||||
ReadTimeout: 30 * time.Second,
|
||||
WriteTimeout: 30 * time.Second,
|
||||
MaxConnWaitTimeout: 30 * time.Second,
|
||||
TLSConfig: nil, // 使用默认配置
|
||||
}
|
||||
|
||||
// 创建基础传输配置
|
||||
transport := &http.Transport{
|
||||
ForceAttemptHTTP2: false, // 服务器不支持HTTP/2
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: false, // 启用证书验证
|
||||
MinVersion: tls.VersionTLS12,
|
||||
MaxVersion: tls.VersionTLS12,
|
||||
CipherSuites: []uint16{
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
},
|
||||
NextProtos: []string{"http/1.1"}, // 禁用ALPN协商
|
||||
},
|
||||
}
|
||||
// 准备请求
|
||||
req := fasthttp.AcquireRequest()
|
||||
defer fasthttp.ReleaseRequest(req)
|
||||
|
||||
// 如果是腾讯的特定域名,使用特殊的TLS配置
|
||||
if strings.HasSuffix(parsedURL.Host, ".qq.com.cn") {
|
||||
transport.DisableCompression = true // 服务器不支持压缩
|
||||
transport.TLSClientConfig.ServerName = parsedURL.Host // 确保SNI正确
|
||||
}
|
||||
req.SetRequestURI(urlStr)
|
||||
req.Header.SetMethod("GET")
|
||||
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
|
||||
|
||||
// 创建HTTP客户端
|
||||
client := &http.Client{
|
||||
Transport: transport,
|
||||
}
|
||||
// 准备响应
|
||||
resp := fasthttp.AcquireResponse()
|
||||
defer fasthttp.ReleaseResponse(resp)
|
||||
|
||||
// 发送 HTTP GET 请求
|
||||
var resp *http.Response
|
||||
// 发送请求
|
||||
var maxRetry = 100
|
||||
var retry = 0
|
||||
for resp, err = client.Get(urlStr); err != nil && retry < maxRetry; resp, err = client.Get(urlStr) {
|
||||
for err = client.Do(req, resp); err != nil && retry < maxRetry; err = client.Do(req, resp) {
|
||||
fmt.Printf("下载失败,正在重试... 错误: %v\n", err)
|
||||
retry++
|
||||
}
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("下载失败: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 检查 HTTP 响应状态码
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", fmt.Errorf("请求失败,状态码: %d", resp.StatusCode)
|
||||
// 检查响应状态码
|
||||
if resp.StatusCode() != fasthttp.StatusOK {
|
||||
return "", fmt.Errorf("请求失败,状态码: %d", resp.StatusCode())
|
||||
}
|
||||
|
||||
// 读取响应内容到内存中以检测文件类型
|
||||
bodyData, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("读取响应内容失败: %v", err)
|
||||
}
|
||||
// 获取响应体
|
||||
bodyData := resp.Body()
|
||||
|
||||
// 获取正确的文件扩展名
|
||||
ext := GetImageExtension(bodyData)
|
||||
|
||||
Reference in New Issue
Block a user