Rehber · Güncelleme 2026-11-06
Golang Proxy Kullanımı: net/http ve Colly’de Rotating Proxy
Golang proxy kullanımı: http.Transport ile kimlikli gateway, istek başına proxy fonksiyonu, keep-alive’ın rotasyona etkisi, Colly’de SetProxyFunc, hız sınırı, SOCKS5.

Golang proxy kullanımı: ayar Transport’ta yapılır
Golang proxy kullanımı tek bir yere bağlıdır: http.Transport. Go’nun standart kütüphanesinde proxy kararı istemcinin (http.Client) değil, onun altındaki taşıma katmanının işidir. Panelden aldığınız host, port, kullanıcı adı ve şifreyi http://kullanici:sifre@host:port biçiminde tek adrese çevirir, bu adresi url.Parse ile ayrıştırır ve Transport’un Proxy alanına http.ProxyURL(u) olarak verirsiniz. Bundan sonra bu Transport’u taşıyan her istemci, her isteği gateway üzerinden gönderir; çıkış IP’sini her istekte gateway seçer.
Kimlik bilgisi için ayrı bir başlık yazmanız gerekmez. Adresin kullanıcı bilgisi dolu olduğunda Transport bunu Base64’e çevirip Proxy-Authorization başlığı olarak kendisi ekler. HTTP hedeflerde başlık her isteğe, HTTPS hedeflerde ise proxy’ye gönderilen CONNECT isteğine girer; tünel kurulduktan sonra TLS içinde giden asıl isteğe proxy bakamaz. Şifrede @, : ya da / gibi karakterler varsa url.UserPassword(kullanici, sifre) ile kaçırılmış biçimde adresi kurmak, elle yazılmış adresteki ayrıştırma hatalarını baştan önler.
Örnekler RotatingProxy kataloğundaki beş ürünle aynı biçimde çalışır; beşi de HTTP, HTTPS ve SOCKS5 kabul eder. IPv4 datacenter, IPv4 residential ve mobile ürünler GB bazlı, IPv6 ürünler port bazlı satılır; Go tarafında bu fark bağlantı kodunu değiştirmez, yalnız hangi sayacı izleyeceğinizi belirler. Adres koda yazılmaz: os.Getenv("PROXY_URL") okunur, boşsa program açık bir hatayla durur. Sessizce proxy’siz devam eden bir scraper, kendi IP’nizle hedefi tararken fark edilmesi en geç olan hatadır.
Varsayılan Transport’u değiştirmek yerine kendi Transport’unuzu kurun: t := &http.Transport{ Proxy: http.ProxyURL(u), MaxIdleConns: 100, MaxIdleConnsPerHost: 20, IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second }; client := &http.Client{ Transport: t, Timeout: 30 * time.Second }. http.DefaultTransport ortam değişkenlerinden proxy okur (ProxyFromEnvironment); kendi Transport’unuzda Proxy alanını açıkça verdiğiniz için HTTP_PROXY değişkeni artık bu istemciyi etkilemez. İki kaynağın aynı anda açık olması, "ayar yaptım ama IP değişmedi" şikâyetinin en sık nedenidir.
İstek başına proxy seçimi: Proxy alanı bir fonksiyondur
Transport’un Proxy alanı sabit bir adres değil, func(*http.Request) (*url.URL, error) imzalı bir fonksiyondur; http.ProxyURL yalnız her çağrıda aynı adresi döndüren bir kısayoldur. Kendi fonksiyonunuzu yazarsanız proxy kararı her istek için ayrı verilir: isteğin hedef alanına, bağlamındaki bir değere ya da üstbilgisine bakıp farklı bir adres döndürebilirsiniz. Rotating gateway ile bu özellik iki işe yarar: aynı gateway’e farklı oturum kimliği ya da ülke parametresiyle çıkmak ve istek türüne göre ürün değiştirmek.
Oturum parametresi gateway’de kullanıcı adına eklenir; sözdizimi panelde tanımlıdır ve gateway mantığı rehberinde ayrıntılı anlatılır. Go tarafında bunun karşılığı, isteğin bağlamına bir oturum anahtarı koyup Proxy fonksiyonunda o anahtara göre adres üretmektir: req.Context().Value(sessionKey) dolu ise kullanıcı adına oturum eki eklenmiş adres, boşsa kimliksiz adres döner. Sepet akışı gibi çok adımlı işler tek oturumda kalır, bağımsız sayfa taramaları her istekte yeni IP alır ve ikisi aynı istemciyi paylaşır.
Fonksiyonun döndürdüğü adres nesnesini her çağrıda yeniden üretmek yerine önceden hazırlanmış birkaç url.URL değerinden seçin; Proxy fonksiyonu her istekte çalışır ve içinde ayrıştırma yapmak gereksiz yük bindirir. Fonksiyon nil döndürürse istek doğrudan gider; bu davranışı hedefinizin alan adına göre proxy’yi atlamak için kullanabilirsiniz, ama kendi IP’nizle gidecek her istek açıkça listelenmiş olmalıdır.
Keep-alive ve bağlantı havuzu: IP neden değişmiyor?
Go’da Transport bağlantıları yeniden kullanır. Proxy üzerinden giden HTTPS isteklerinde havuz, proxy adresi ile hedef çifti için açılmış CONNECT tünellerini tutar; aynı hedefe art arda giden istekler boşta bir tünel varsa onu kullanır. Gateway tarafında rotasyon bağlantı başına yapılıyorsa aynı tünelden geçen istekler aynı çıkış IP’sinde kalır. Beş istek atıp beşinde de aynı IP’yi gören geliştiricinin ilk bakacağı yer kendi Transport ayarıdır.
Her istekte yeni IP istiyorsanız iki seçenek var. Birincisi Transport’ta DisableKeepAlives: true; her istek yeni TCP bağlantısı ve yeni tünel açar, gateway her bağlantıda yeni IP seçer, bedeli her istekte TLS el sıkışmasının tekrarlanmasıdır. İkincisi, gateway’in istek başına rotasyon modunu kullanmak; bu durumda keep-alive açık kalabilir, çünkü IP kararı bağlantıya değil isteğe bağlıdır. Hangi modun geçerli olduğu ürüne ve panel ayarına bağlıdır; rotasyon aralığı rehberi iki modun hangi işe uyduğunu anlatır.
Tersi de aynı derecede önemlidir: oturum kimlikli adreslerle çalışırken keep-alive açık kalmalı, aksi halde her istek yeni tünel açar ve gereksiz el sıkışmasıyla gecikme artar. Bir Transport bütün süreç boyunca tek kez kurulur ve paylaşılır; her istekte yeni http.Client ya da yeni Transport yaratmak havuzu işlevsiz bırakır, dosya tanımlayıcı tüketir ve "too many open files" hatasına kadar gider. Adres başına bir Transport yeter.
Doğrulama için istemci IP’sini düz metin döndüren bir adres kullanın ve aynı istemciyle art arda beş istek atıp sonuçları bir map’te toplayın. Önce varsayılan ayarla, sonra DisableKeepAlives: true ile çalıştırın. Birinci sayı 1, ikinci sayı 5’e yakınsa gateway bağlantı başına rotasyon yapıyor demektir; iki sayı da 1 ise oturum parametresi açık kalmıştır ya da istekler başka bir Transport’tan çıkıyordur. İki sayı da 5’e yakınsa gateway istek başına rotasyonda çalışıyordur ve keep-alive’ı kapatmanız gerekmez.
Colly’de proxy: SetProxy, SetProxyFunc ve round-robin
Colly, altında yine http.Transport taşır; proxy ayarı aynı mantıkla çalışır, yalnız iki kısayol sunar. c.SetProxy("http://kullanici:sifre@host:port") tek adresi bütün isteklere uygular. c.SetProxyFunc(fn) ise Transport’un Proxy alanına doğrudan sizin fonksiyonunuzu koyar; imza colly.ProxyFunc, yani func(*http.Request) (*url.URL, error). Yukarıdaki oturum kimlikli seçim mantığı Colly’de de aynen kullanılır. İsterseniz c.WithTransport(t) ile baştan kendi Transport’unuzu verip havuz ve zaman aşımı ayarlarını da elinizde tutarsınız.
Kütüphanenin proxy paketinde hazır bir döngü var: proxy.RoundRobinProxySwitcher("adres1", "adres2") çağrısı bir ProxyFunc döndürür ve listedeki adresleri sırayla kullanır; http, https ve socks5 şemalarını tanır, şema yazılmazsa http varsayar. Rotating gateway ile bu döngü çoğu zaman gereksizdir; tek adres yeter, IP’yi gateway değiştirir. Döngü, aynı gateway’in iki farklı ülke ya da iki farklı oturum varyantını sırayla kullanmak istediğinizde anlam kazanır.
Bilinmesi gereken bir ayrıntı var: proje geçmişinde SetProxyFunc ile verilen listenin keep-alive açıkken yalnız başarısız isteklerde ilerlediği bildirildi ve düzeltme olarak keep-alive’ın kapatılması tartışıldı. Birden fazla adresle döngü kuruyorsanız kendi sürümünüzde beş istekli deneyi tekrarlayın; listedeki adresler sırayla kullanılmıyorsa Transport’ta DisableKeepAlives: true verin. Tek gateway adresiyle çalışıyorsanız bu konu sizi ilgilendirmez.
Sürüm farkı içe aktarma yolunda görünür: eski seri github.com/gocolly/colly, güncel seri github.com/gocolly/colly/v2 ve proxy paketi github.com/gocolly/colly/v2/proxy yolundadır. Örnekleri kendi go.mod dosyanızdaki sürüme göre okuyun; iki yolu aynı projede karıştırmak, aynı adlı iki ayrı paketle çalışmak demektir ve ProxyFunc tipleri birbirine atanamaz.
Hız sınırı, zaman aşımı ve yeniden deneme
Colly’de hız c.Limit(&colly.LimitRule{ DomainGlob: "*", Parallelism: 4, Delay: 500 * time.Millisecond, RandomDelay: 300 * time.Millisecond }) ile sınırlanır. Parallelism aynı anda açık istek sayısını, Delay iki istek arasındaki en az beklemeyi, RandomDelay buna eklenen rastgele payı belirler. Rotating IP bu sınırı kaldırmaz: hedef hız sınırını IP’ye değil çoğu zaman oturuma, başlık setine ve tempoya göre uygular. 429 yanıtı IP değişse de gelir; o rehberde tempo kuralları ayrıntılı anlatılıyor.
Zaman aşımı iki yerde ayarlanır. c.SetRequestTimeout(30 * time.Second) isteğin toplam süresini sınırlar; Transport’taki TLSHandshakeTimeout ve ResponseHeaderTimeout ise aşamaları ayrı ayrı sınırlar. Proxy üzerinden giden istekte bağlantı kurma süresi doğrudan erişime göre uzar, çünkü araya proxy’nin hedefe bağlanma süresi girer; bağlantı zaman aşımını birkaç saniyenin altına çekmeyin. Düz net/http kullanıyorsanız http.Client.Timeout toplam süreyi, Transport’un DialContext alanındaki net.Dialer.Timeout bağlantı süresini belirler.
Yeniden deneme Colly’de c.OnError(func(r *colly.Response, err error) { ... }) içinde kurulur. Hata sınıfına göre ayırın: bağlantı hatası, zaman aşımı ve 5xx yanıtlarda r.Request.Retry() ile tekrar deneyin, 403 ve 404 gibi yanıtlarda denemeyin. Retry çağrısı isteği aynı Collector’dan yeniden gönderir; Proxy fonksiyonunuz yeniden çalışır ve bağlantı başına rotasyonda yeni IP alır. Deneme sayısını bir sayaçla sınırlayın ve denemeler arasına artan bekleme koyun; üstel bekleme kurgusu retry ve backoff rehberinde anlatılıyor.
407 Proxy Authentication Required kodu üç şeyden birini söyler: adres kullanıcı bilgisi taşımıyor, şifredeki özel karakter kaçırılmamış ya da IP izni modunda sunucunuzun IP’si panelde kayıtlı değil. Go’da HTTPS hedefte bu hata "Proxy Authentication Required" metnini içeren bir CONNECT hatası olarak döner, HTTP hedefte düz 407 yanıtı gelir. Önce u.User.Username() ve u.User.Password() değerlerini yazdırıp adresi ayrıştırmanın ne okuduğunu görün; diğer bağlantı hataları için 407 ve rotasyon hataları rehberine bakın.
SOCKS5: socks5 şeması ve golang.org/x/net/proxy
Go’nun standart Transport’u proxy adresinde socks5 şemasını doğrudan tanır: socks5://kullanici:sifre@host:port adresini http.ProxyURL ile verdiğinizde ek paket gerekmez, kimlik doğrulaması da adresten alınır. SOCKS5 ile proxy, HTTP başlıklarını görmez; TCP bağlantısını hedefe taşır. HTTPS hedeflerde HTTP CONNECT ile SOCKS5 arasında kodunuz açısından fark yoktur; ikisinde de TLS istemcinizle hedef arasında kurulur.
Daha ince denetim gerektiğinde golang.org/x/net/proxy paketi kullanılır: proxy.SOCKS5("tcp", "host:port", &proxy.Auth{User: u, Password: p}, proxy.Direct) çağrısı bir Dialer döndürür; bunu Transport’un DialContext alanına bağlarsınız. Bu yol, HTTP dışındaki protokolleri de aynı proxy üzerinden geçirmek ya da bağlantı kurma aşamasına kendi zaman aşımınızı ve kayıt mantığınızı koymak için gerekir. Yalnız HTTP istekleri gönderiyorsanız standart şema yeterlidir ve daha az kod demektir.
Hangisini seçeceğiniz hedefe ve araca bağlıdır. HTTP CONNECT, çoğu kurumsal ağda ve hata ayıklama araçlarında daha kolay izlenir; SOCKS5, HTTP olmayan bir protokolü proxy’den geçirmeniz gerektiğinde tek seçenektir. Ürün tarafında ikisi de aynı kotadan düşer; GB bazlı üründe sayaç aktarılan veriyi sayar.
Kurulum sonrası kontrol listesi
Adres ortam değişkeninden okunuyor ve boşsa program duruyor mu? Transport tek kez kurulup paylaşılıyor mu? Proxy alanı açıkça verildiği için HTTP_PROXY değişkeni devre dışı kaldı mı? Beş istekli IP deneyi hem varsayılan ayarla hem DisableKeepAlives ile çalıştırıldı ve sonuç beklenen rotasyon moduna uyuyor mu? Oturum kimlikli ve kimliksiz adresler ayrı url.URL değerleri olarak hazır mı?
Colly tarafında: LimitRule tanımlı ve Parallelism hedefin kaldırabileceği düzeyde mi? OnError içinde yeniden deneme sayısı sınırlı ve hata sınıfına göre mi? SetRequestTimeout verildi mi? İçe aktarma yolları tek bir Colly sürümüne mi işaret ediyor? Cevabı "hayır" olan her madde, üretimde ilk günlerde ortaya çıkan bir sorunu önceden gösterir.
Sık sorulan sorular
Go’da proxy kullanıcı adı ve şifresi URL’ye yazılabilir mi? Evet. http.ProxyURL’e verilen adreste kullanıcı bilgisi varsa Transport, Proxy-Authorization başlığını Basic yöntemiyle kendisi üretir. Özel karakterli şifreleri url.UserPassword ile kurun; elle yazılmış adreste kaçırılmamış bir @ karakteri host adını bölüp "no such host" hatasına yol açar.
Her istekte farklı IP için her seferinde yeni http.Client mi gerekir? Hayır. Yeni istemci açmak havuzu boşa çıkarır ve kaynak tüketir. Bağlantı başına rotasyonda tek Transport’ta DisableKeepAlives: true yeterlidir; istek başına rotasyon modunda hiçbir ayar gerekmez. Aynı IP’de kalmak istediğiniz işlerde ise keep-alive açık kalır ve oturum kimliği kullanılır.
Colly’de proxy istek bazında nasıl değişir? SetProxyFunc’a kendi fonksiyonunuzu verin; fonksiyon her istekte çalışır ve isteğin bağlamına ya da hedef alanına göre farklı adres döndürebilir. Hazır RoundRobinProxySwitcher ise listeyi sırayla döndürür; tek gateway adresiyle çalışırken gerekmez.
HTTP_PROXY ortam değişkeni otomatik okunur mu? http.DefaultTransport okur, çünkü Proxy alanı ProxyFromEnvironment ile kurulmuştur. Kendi Transport’unuzda Proxy alanını açıkça verdiğinizde ortam değişkeni yok sayılır. Ortam değişkenine dayanmak istiyorsanız Proxy: http.ProxyFromEnvironment yazın ve NO_PROXY ile hariç tutulacak alanları da ayarlayın.
Kota Go tarafında nasıl ölçülür? GB bazlı üründe gelen ve giden veri sayılır. Yanıt gövdesini io.Copy ile okurken dönen bayt sayısını toplayın ya da Content-Length başlığını kaydedin; istek sayısına bölünce ortalama yanıt boyutu çıkar, kota tahmininin ana girdisi budur. Port bazlı IPv6 ürünlerde bu sayaç gerekmez; orada sınır eşzamanlı bağlantıdır.
