Вы путаете прямой и обратный прокси.
Концептуально это работает так:
Обратные прокси
- развернуто около серверной части соединения
- притворяется источником
- контролируются владельцем или от имени владельца сайта
- по сути своей неизвестен агенту пользователя
Переадресация прокси
- развернуты на стороне клиента соединения
- контролируются или от имени пользовательского агента
- явно настроены в пользовательском агенте
(Реальность сложнее, чем это, конечно, но этого достаточно, чтобы выделить различия).
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. Клиент не знает и не контролирует, что происходит после прокси.
Если вы не можете изменить запрос, вы можете установить функцию Transport.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)