我想传递 POST 请求的转发代理服务器列表
目前我只能使用单个转发代理来完成此操作
serverProxy := "http://user:password@123.45.67.89:3128"
request, error := http.NewRequest("POST", httpposturl, bytes.NewBuffer(requestJSON))
request.Header.Set("Content-Type", "application/json; charset=UTF-8")
proxyURL, _ := url.Parse(serverProxy)
proxy := http.ProxyURL(proxyURL)
transport := &http.Transport{Proxy: proxy}
client := &http.Client{Transport: transport}
Run Code Online (Sandbox Code Playgroud)
我想做的是将列表传递给url.Parse并希望它使用循环平衡来使用它们
所以像这样
serverProxy := "http://user:password@123.45.67.89:3128, http://user:password@223.45.67.89:3128"
Run Code Online (Sandbox Code Playgroud)
然后它将选择要使用的代理服务器并在请求中轮换它们
这可能吗?
更新:
我希望能够像这样传递旋转的代理服务器
proxyServer := roundRobin("http://round:robin@123.45.67.89:3128, http://robin:round@223.45.67.89:3128")
fmt.Println("proxy server used", proxyServer, "\n")
transport := &http.Transport{Proxy: proxyServer}
client := &http.Client{Transport: transport}
Run Code Online (Sandbox Code Playgroud)
这是蒙太奇的回答和解释:
要求是通过代理以循环方式转发请求
由于我们使用的http.Client是发出请求,因此我们可以查看http.Client文档,看看它是否提供通过代理转发请求的任何支持,当我们查看文档时,我们可以看到它确实支持传递代理,我们可以通过将传递给的http.Transport类型传递该代理http.Client。http.Transport通过字段获取代理,Proxy该字段接受返回的 func *url.URL,并且包内提供了error类似 和 等现有方法http.ProxyURL,我们可以使用它们来传递代理,但这些方法的问题是它们只采用单个代理服务器,这不能解决我们的问题因此,我们需要创建自己的函数,该函数接受多个代理服务器 URL 并在它们之间进行循环。http.ProxyFromEnvironmenthttphttp.Transport
如果我们将现有方法实现之一视为创建我们自己的方法的基础,那么我们就http.ProxyURL可以找到该实现here。我复制了下面的实现
func ProxyURL(fixedURL *url.URL) func(*Request) (*url.URL, error) {
return func(*Request) (*url.URL, error) {
return fixedURL, nil
}
}
Run Code Online (Sandbox Code Playgroud)
我们可以看到它是一个简单的闭包,它接受单个 url 并返回一个闭包函数,然后该函数返回作为参数传入的 url。所以我们可以以此为基础并创建我们自己的循环闭包函数
func roundRobin(proxies ...string) func(*http.Request) (*url.URL, error) {
var urls []*url.URL
for _, proxy := range proxies {
u, err := url.Parse(proxy)
if err != nil {
log.Fatal(err)
}
urls = append(urls, u)
}
var mu sync.Mutex
var i, lenUrls int = 0, len(urls)
return func(r *http.Request) (*url.URL, error) {
mu.Lock()
i = (i + 1) % lenUrls
u := urls[i]
mu.Unlock()
return u, nil
}
}
Run Code Online (Sandbox Code Playgroud)
让我们回顾一下roundRobin函数的实现,它是一个可变参数函数,它接受字符串格式的代理 url 作为参数,在内部url.URL通过使用解析字符串进行转换url.Parse,然后使用解析后的内容url.URL创建 url 片段[]*url.URL,然后将其用于转发以循环方式请求
完整的工作示例如下:
package main
import (
"fmt"
"log"
"net/url"
"net/http"
"sync"
)
func roundRobin(proxies ...string) func(*http.Request) (*url.URL, error) {
var urls []*url.URL
for _, proxy := range proxies {
u, err := url.Parse(proxy)
if err != nil {
log.Fatal(err)
}
urls = append(urls, u)
}
var mu sync.Mutex
var i, lenUrls int = 0, len(urls)
return func(r *http.Request) (*url.URL, error) {
mu.Lock()
i = (i + 1) % lenUrls
u := urls[i]
mu.Unlock()
return u, nil
}
}
func main() {
proxyFn := roundRobin("http://user:password@123.45.67.89:3128", "http://user:password@223.45.67.89:3128")
transport := &http.Transport{Proxy: proxyFn}
client := &http.Client{Transport: transport}
req, err := http.NewRequest("POST", "http://example.com", nil)
req.Header.Set("Content-Type", "application/json; charset=UTF-8")
resp, err := client.Do(req)
if err != nil {
fmt.Println(resp)
}
fmt.Println(proxyFn(nil))
fmt.Println(proxyFn(nil))
}
Run Code Online (Sandbox Code Playgroud)
另一个版本
package main
import (
"fmt"
"log"
"net/http"
"net/url"
"sync"
)
func praseUrls(proxies ...string) (urls []*url.URL) {
for _, proxy := range proxies {
u, err := url.Parse(proxy)
if err != nil {
log.Fatal(err)
}
urls = append(urls, u)
}
return
}
func roundRobin(max int) func() int {
var i int
return func() int {
i = (i + 1) % max
return i
}
}
func proxyFn(urls []*url.URL) func(*http.Request) (*url.URL, error) {
var m sync.Mutex
fn := roundRobin(len(urls))
return func(*http.Request) (*url.URL, error) {
m.Lock()
u := urls[fn()]
m.Unlock()
return u, nil
}
}
func main() {
proxies := []string{"http://user:password@123.45.67.89:3128", "http://user:password@223.45.67.89:3128"}
urls := praseUrls(proxies...)
transport := &http.Transport{Proxy: proxyFn(urls)}
client := &http.Client{Transport: transport}
req, err := http.NewRequest("POST", "http://example.com", nil)
req.Header.Set("Content-Type", "application/json; charset=UTF-8")
resp, err := client.Do(req)
if err != nil {
fmt.Println(resp)
}
}
Run Code Online (Sandbox Code Playgroud)
注意:最好从 env 变量传递代理 url,这将有助于防止任何代理服务器更改或添加新代理服务器
| 归档时间: |
|
| 查看次数: |
1119 次 |
| 最近记录: |