Я пытаюсь выполнить запрос http/s через рабочий прокси.
У меня есть рабочий пример в устаревшем проекте в узле JS, где использование собственной библиотеки Node.js https (require('https')) может сделать запрос, если он используется со следующим объектом параметров:
{
host: "<actual target url>"
hostname: "<proxy ip>"
}
Например, чтобы сделать https-запрос к example.com через прокси 1.1.1.1, я буду использовать:
{
host: "http://example.com"
hostname: "1.1.1.1"
}
В Golang я пробовал несколько задокументированных вариантов. В частности, я ожидаю:
proxyUrl, _ := url.Parse("<proxy ip>")
myClient := &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxyUrl)}}
resp, err := myClient.Get("https://<actual target url>/...")
В результате прокси отклоняет соединение, указывая на неточность в запросе. (err существует, и соответственно есть nil)
Сам прокси-сервер представляет собой экземпляр NGINX, настроенный в соответствии со следующим принципом:
https://gist.github.com/selfish/6e858eb17aa82971d25b21775e9649cb#file-nginx-conf
Может ли кто-нибудь помочь понять разницу в обработке HTTP для Node.js и Golang?
сервер nginx получил запрос от вашего клиента go?
nginx — это обратный прокси. В Go не требуется специальной настройки. Просто отправьте запрос на адрес и порт nginx. Transport.Proxy предназначен для прямых прокси-серверов, обычно используемых для кэширования и/или фильтрации.
Питер прав. В вашем примере node.js вы на самом деле не говорите ему использовать HTTP-прокси - вы просто говорите, что для доступа к цели следует использовать другой IP-адрес, чем тот, который возвращается DNS. Таким образом, он выполняет обычный HTTP-запрос. Вместо этого ваш код Go выполняет запрос прокси-сервера HTTP, который отличается от обычного запроса HTTP и не ожидается обратным прокси-сервером. Таким образом, это терпит неудачу.
@Питер действительно был прав. Если вы хотите добавить это в качестве ответа, я приму. Спасибо!!





Вы путаете прямые и обратные прокси.
Концептуально это работает так:
Обратные прокси
Переадресация прокси
(Реальность, конечно, сложнее, но этого достаточно, чтобы подчеркнуть различия).
Internet || Invisible to
+ || User Agent
| ||
+------------+ +---------------+ | +---------------+ || +--------+
| | | | | | | || | |
| User Agent +---->+ Forward Proxy +-------->+ Reverse Proxy +----->+ Origin |
| | | | | | | || | |
+------------+ +---------------+ | +---------------+ || +--------+
| ||
+ ||
||
nginx — это обратный прокси-сервер, но, устанавливая поле Transport.Proxy, вы обращаетесь с ним как с прямым прокси-сервером. Это запрос, который видит nginx:
CONNECT example.com:443 HTTP/1.1
Host: example.com:443
User-Agent: Go-http-client/1.1
По сути, это означает: «Установите TCP-соединение с example.com:443, а затем действуйте как тупой TCP-прокси». Поскольку nginx является обратным прокси, он справедливо путается при столкновении с запросом CONNECT.
Чтобы отправить запрос на конкретный обратный прокси-сервер, вам просто нужно изменить URL-адрес запроса и, возможно, заголовок хоста (это зависит от того, ожидает ли nginx определенный server_name). Никакой специальной настройки клиента не требуется.
Предполагая, что nginx работает на 198.51.100.1:
req, _ := http.NewRequest("GET", "http://198.51.100.1", nil)
req.Host = "example.com" // if necessary
res, _ := http.DefaultClient.Do(req)
Это приводит к отправке следующего запроса на адрес 198.51.100.1:80:
GET / HTTP/1.1
Host: example.com
User-Agent: Go-http-client/1.1
Accept-Encoding: gzip
Обратите внимание, что обратный прокси-сервер полностью зависит от того, попадет ли запрос на сайт example.com. Клиент не знает и не контролирует, что происходит после прокси.
Если вы не в состоянии изменить запрос, вы можете установить функцию Транспорт.DialContext таким образом, чтобы ваш прокси всегда вызывался, независимо от URL-адреса запроса и заголовка хоста. Это приводит к тому же запросу, что и выше, и должен быть эквивалентен вашему коду JavaScript:
c := &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
return (&net.Dialer{}).DialContext(ctx, "tcp", "198.51.100.1:80")
// Or 198.51.100.1:443 if nginx has TLS enabled, although that almost
// certainly causes TLS validation errors because a certificate for
// example.com is expected.
},
},
}
req, _ := http.NewRequest("GET", "http://example.com", nil)
res, _ := c.Do(req)
Это золото. Спасибо!
можешь вставить ошибку?