You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

186 lines
4.6 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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
}