package tools import ( "crypto/tls" "fmt" C "github.com/metacubex/mihomo/constant" "golang.org/x/net/context" "io" "log" "net" "net/http" "net/url" "sync" "time" ) var dialerBaidu = &net.Dialer{ Resolver: &net.Resolver{ PreferGo: true, Dial: func(ctx context.Context, network, address string) (net.Conn, error) { d := net.Dialer{ Timeout: time.Duration(5000) * time.Millisecond, } return d.DialContext(ctx, "udp", "180.76.76.76:53") }, }, } var dialBaiduContext = func(ctx context.Context, network, addr string) (net.Conn, error) { return dialerBaidu.DialContext(ctx, network, addr) } // HttpGetByProxy 使用代理访问指定的URL并返回响应数据 func HttpGetByProxy(requestUrl, httpProxyUrl string) ([]byte, error) { // 拼接代理地址 uri, _ := url.Parse(httpProxyUrl) // 创建一个带代理的HTTP客户端 client := http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, Proxy: http.ProxyURL(uri), }, Timeout: 20 * time.Second, } // 创建一个GET请求 req, err := http.NewRequest(http.MethodGet, requestUrl, nil) if err != nil { log.Printf("HttpGetByProxy http.NewRequest %s %v\n", requestUrl, err) return nil, err } req.Header.Set("Accept-Encoding", "utf-8") req.Header.Set("Accept", "*/*") req.Header.Set("User-Agent", C.UA) // 发送请求并获取响应 resp, err := client.Do(req) if err != nil { log.Printf("HttpGetByProxy client.Do %s %v\n", requestUrl, err) return nil, err } defer func(Body io.ReadCloser) { err := Body.Close() if err != nil { // 处理异常情况 } }(resp.Body) // 读取响应数据 data, err := io.ReadAll(resp.Body) if err != nil { log.Printf("HttpGetByProxy io.ReadAll %s %v\n", requestUrl, err) return nil, err } if resp.StatusCode != http.StatusOK { log.Printf("HttpGetByProxy StatusCode %s %d\n", requestUrl, resp.StatusCode) return nil, fmt.Errorf("StatusCode %d", resp.StatusCode) } return data, nil } // HttpGet 使用HTTP GET方法请求指定的URL,并返回响应的数据和可能的错误。 func HttpGet(requestUrl string) ([]byte, error) { timeOut := 15 * time.Second return HttpGetWithTimeout(requestUrl, timeOut, true) } // HttpGetWithTimeout 使用HTTP GET方法请求指定的URL,并返回响应的数据和可能的错误。 func HttpGetWithTimeout(requestUrl string, outTime time.Duration, needDail bool) ([]byte, error) { client := http.Client{ Timeout: outTime, // 请求超时时间 } if needDail { client.Transport = &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // 安全证书验证关闭 DialContext: dialBaiduContext, } } req, err := http.NewRequest(http.MethodGet, requestUrl, nil) // 创建一个新的GET请求 if err != nil { log.Printf("HttpGetWithTimeout http.NewRequest %s %v\n", requestUrl, err) return nil, err } req.Header.Set("Accept-Encoding", "utf-8") // 设置响应内容编码为utf-8 req.Header.Set("Accept", "*/*") // 设置响应内容类型为全部 req.Header.Set("User-Agent", C.UA) // 设置用户代理为C.UA resp, err := client.Do(req) // 发送请求并获取响应 if err != nil { log.Printf("HttpGetWithTimeout client.Do %s %v\n", requestUrl, err) return nil, err } defer func(Body io.ReadCloser) { err := Body.Close() if err != nil { // 处理关闭响应体的错误 } }(resp.Body) data, err := io.ReadAll(resp.Body) // 读取响应体的数据 if err != nil { log.Printf("HttpGetWithTimeout io.ReadAll %s %v\n", requestUrl, err) return nil, err } if resp.StatusCode != http.StatusOK { log.Printf("HttpGetWithTimeout StatusCode %s %d\n", requestUrl, resp.StatusCode) return nil, fmt.Errorf("StatusCode %d", resp.StatusCode) } return data, nil // 返回响应数据和无错误 } // ConcurrentHttpGet 并发获取指定URL的HTTP内容 func ConcurrentHttpGet(url string) (all []byte) { // 开启多线程请求 cLock := sync.Mutex{} done := make(chan bool, 1) length := 128 wg := sync.WaitGroup{} go func() { wg.Add(1) defer wg.Done() content, err := HttpGetByProxy(url, "") if err == nil { cLock.Lock() if all == nil && len(content) > length { all = content } cLock.Unlock() done <- true } }() go func() { wg.Add(1) defer wg.Done() content, err := HttpGet(url) if err == nil { cLock.Lock() if all == nil && len(content) > length { all = content } cLock.Unlock() done <- true } }() go func() { time.Sleep(5 * time.Second) wg.Wait() done <- true }() select { case <-done: case <-time.After(20 * time.Second): } return }