Geonode logo
Geonode Team

Geonode Team

Diperbarui: 7 Oktober 2026

Diterbitkan: 2 September 2026

Cara Menggunakan Proxy dengan SuperAgent di Node.js

SuperAgent tidak memiliki opsi proxy bawaan. Anda bisa menambahkan ekstensi atau menggunakan agen HTTP, dan kedua pendekatan tersebut menjadi rumit akibat konflik penamaan: istilah "`.agent()`" di SuperAgent sudah memiliki arti yang sama sekali berbeda. Konflik tersebut menimbulkan kebingungan khusus di mana pengguna mengira mereka telah mengonfigurasi proxy, padahal yang mereka konfigurasi sebenarnya adalah "cookie jar". Panduan ini membahas kedua cara tersebut, terminologi yang digunakan, serta pemeriksaan yang akan memberi tahu Anda mana yang sebenarnya berlaku.

Kami adalah Geonode dan kami menjual proxy, jadi ini adalah panduan untuk menggunakan produk kami dengan klien tertentu. Bagian yang wajib dibaca meskipun Anda melewatkan bagian lainnya: periksa alamat keluar setelah konfigurasi, karena pengaturan proxy yang tidak berfungsi sama sekali tidak akan menampilkan pesan kesalahan apa pun. SuperAgent akan dengan senang hati mengirimkan permintaan Anda secara langsung, mengembalikan kode status 200, dan tidak memberikan indikasi apa pun bahwa proxy telah dilewati. Bagian verifikasi ini hanya terdiri dari empat baris, dan inilah yang membedakan antara mengetahui dan sekadar mengasumsikan.

Perhatikan juga bahwa SuperAgent juga berfungsi di peramban, di mana hal ini tidak berlaku — peramban tidak dapat diperintahkan untuk menggunakan proxy dari JavaScript, sehingga semua yang dijelaskan di sini hanya berlaku untuk Node.

Masalah Terminologi

Mari kita perjelas hal ini terlebih dahulu, karena hal ini dapat menyebabkan kesalahan yang nyata.

Di SuperAgent, perintah .agent() tanpa argumen akan membuat salinan SuperAgent yang menyimpan cookie. Dokumentasi secara eksplisit menyatakan: "Di Node, SuperAgent tidak menyimpan cookie secara default, tetapi Anda dapat menggunakan metode .agent() untuk membuat salinan SuperAgent yang menyimpan cookie. Setiap salinan memiliki tempat penyimpanan cookie tersendiri."

const agent = request.agent();
await agent.post("/login").send({ user, pass });
await agent.get("/cookied-page");   // session cookie carried over

Agent tersebut juga memiliki pengaturan default: "Metode permintaan biasa yang dipanggil pada agent akan digunakan sebagai default untuk semua permintaan yang dibuat oleh agent tersebut."

Sementara itu, .agent(httpAgent) dengan argumen menetapkan http.Agent Node untuk permintaan tersebut, yang merupakan tempat dukungan proxy berada.

Nama metode yang sama, dua fungsi yang tidak terkait, dibedakan hanya berdasarkan apakah Anda memberikan argumen atau tidak. Jika Anda telah membaca tentang agen SuperAgent dan agen proxy dalam sesi yang sama, hal ini perlu dipahami dengan jelas sebelum Anda mulai menulis kode apa pun.

Rute Pertama: Agen Proksi

Pendekatan yang disarankan, dan alasannya adalah kemudahan pemeliharaan.

import request from "superagent";
import { HttpsProxyAgent } from "https-proxy-agent";

const agent = new HttpsProxyAgent("http://myuser:mypass@proxy.example.com:9000");

const res = await request
  .get("https://api.example.com/items")
  .agent(agent);

Untuk SOCKS, ganti paketnya:

import { SocksProxyAgent } from "socks-proxy-agent";
const agent = new SocksProxyAgent("socks5h://proxy.example.com:1080");

Perhatikan socks5h

, bukan socks5

. Varian h

menyelesaikan nama host di proxy, bukan secara lokal, yang mencegah permintaan DNS dikirim ke resolver Anda sendiri sementara lalu lintas Anda keluar melalui tempat lain — kebocoran yang secara diam-diam menghilangkan tujuan penggunaan proxy untuk geolokasi.

Dan proxy-agent

menangani protokol apa pun yang ditentukan oleh URL, yang berguna ketika proxy berasal dari konfigurasi:

import { ProxyAgent } from "proxy-agent";
const agent = new ProxyAgent();   // reads http_proxy / https_proxy / no_proxy

Mengapa paket-paket ini daripada ekstensi SuperAgent: ketiganya dipelihara secara aktif. Berdasarkan pemeriksaan terhadap registri npm pada September 2026, proxy-agent

berada pada versi 8.0.2, https-proxy-agent

pada versi 9.1.0, dan socks-proxy-agent

pada versi 10.1.0, semuanya diterbitkan pada Juni 2026.

Rute Kedua: superagent-proxy

Ekstensi yang dirancang khusus, beserta keterbatasannya.

import request from "superagent";
import superagentProxy from "superagent-proxy";

superagentProxy(request);

const res = await request
  .get("https://api.example.com/items")
  .proxy("http://myuser:mypass@proxy.example.com:9000");

Berkas README-nya menjelaskan bahwa ekstensi ini memperluas "kelas Request dari superagent dengan fungsi .proxy(uri)", dan menyebutkan bahwa "ekstensi ini didukung oleh modul proxy-agent".

Antarmuka pemrogramannya (API) lebih baik daripada sekadar meneruskan sebuah agen. Panggilan .proxy(uri) lebih mudah dibaca dalam rantai kode, dan menerima URI "HTTP, HTTPS, atau SOCKS", dengan mendelegasikan pemilihan protokol ke proxy-agent.

Perlu diperhatikan tanggal rilisnya. superagent-proxy berada pada versi 3.0.0, yang dirilis pada September 2021 — kira-kira berusia lima tahun pada saat artikel ini ditulis, sementara dependensi dasarnya, proxy-agent, terus mengalami pembaruan. Modul ini tidak dianggap usang dan tidak rusak, tetapi merupakan pembungkus tipis yang tidak mengalami pembaruan sementara komponen yang dibungkusnya terus berkembang.

Konsekuensi praktisnya: jika Anda sudah menggunakannya dan berfungsi dengan baik, tidak ada urgensi. Untuk kode baru, menggunakan agen proxy secara langsung hanya memerlukan satu baris kode tambahan dan menghilangkan lapisan yang sudah usang dari pohon dependensi Anda — dan karena ekstensi ini merupakan pembungkus di sekitar agen tersebut, Anda tidak kehilangan apa pun kecuali sintaksnya.

Pastikan Benar-Benar Berfungsi

Empat baris kode yang paling penting.

const res = await request
  .get("https://api.ipify.org?format=json")
  .agent(agent);

console.log(res.body);

Jalankan perintah tersebut dengan dan tanpa agen. Jika alamatnya tidak berubah, berarti proxy tidak ada dalam jalur. SuperAgent tidak akan menampilkan kesalahan, peringatan, maupun permintaan yang gagal saat hal ini terjadi — lalu lintas data hanya akan langsung diteruskan.

Tiga alasan mengapa konfigurasi sering kali tidak berfungsi:

Anda memanggil .agent() tanpa argumen, sehingga membuat salinan SuperAgent yang menyimpan cookie, bukan mengatur agen HTTP. Ini adalah jebakan terminologi, dan hal ini menyebabkan gejala persis seperti ini.

Anda menerapkan agen ke permintaan yang salah. Rantai SuperAgent berlaku per permintaan, sehingga agen yang ditetapkan pada satu panggilan tidak berlaku untuk panggilan berikutnya. Untuk perilaku yang konsisten, bungkus pembuatan permintaan dalam sebuah fungsi.

Jenis agen tidak sesuai dengan target. Agen "HttpsProxyAgent" menangani target HTTPS; target HTTP biasa mungkin memerlukan varian HTTP. Fitur "proxy-agent" mengatasi hal ini dengan memilihkan untuk Anda.

Untuk proxy yang ditargetkan secara geografis, pemeriksaan alamat saja tidak cukup. Verifikasi berdasarkan hasil — minta sesuatu yang benar-benar berbeda antar wilayah dan pastikan responsnya berubah. Layanan pencarian yang melaporkan negara yang benar sementara API Anda mengembalikan data dari wilayah asal Anda berarti penargetan tidak tepat sasaran, yang merupakan pola kegagalan diam-diam yang kami jelaskan dalam mengapa pengujian proxy penting.

Batas Waktu Melalui Proxy

Model batas waktu SuperAgent sangat baik, dan layak digunakan dengan benar ketika proxy menambah latensi.

Dokumentasi tersebut menjelaskan dua pengaturan. req.timeout({deadline: ms})

— atau req.timeout(ms)

— "menetapkan batas waktu bagi seluruh permintaan (termasuk semua unggahan, pengalihan, dan waktu pemrosesan server) untuk diselesaikan. Jika respons tidak sepenuhnya diunduh dalam waktu tersebut, permintaan akan dibatalkan." Dan req.timeout({response: ms})

"menetapkan waktu maksimum untuk menunggu kedatangan byte pertama dari server, tetapi tidak membatasi berapa lama proses unduhan keseluruhan dapat berlangsung."

Saran dalam dokumentasi mengenai penentuan ukuran ini sangat relevan dengan permintaan yang melalui proxy: "Batas waktu respons harus setidaknya beberapa detik lebih lama daripada waktu yang dibutuhkan server untuk merespons, karena waktu tersebut juga mencakup waktu untuk melakukan pencarian DNS, koneksi TCP/IP dan TLS, serta waktu untuk mengunggah data permintaan."

Melalui proxy, setiap fase tersebut memakan waktu lebih lama. Titik keluar (exit) perumahan menambah latensi nyata per permintaan, dan hal ini disebabkan oleh jarak, bukan gangguan.

const res = await request
  .get("https://api.example.com/items")
  .agent(agent)
  .timeout({ response: 15000, deadline: 60000 });

Dokumentasi tersebut merekomendasikan penggunaan keduanya, dan alasannya sama seperti di tempat lain: batas waktu respons (response timeout) mendeteksi server yang tidak pernah merespons, sedangkan batas waktu akhir (deadline) mendeteksi server yang merespons tetapi kemudian mengirim data secara bertahap. Tidak ada satu pun yang dapat menangani kedua kasus tersebut secara terpisah.

Tentukan nilai-nilai berdasarkan pengukuran melalui proxy, bukan berdasarkan kebiasaan, atau Anda akan menimbulkan kegagalan yang tampak seperti proxy rusak, padahal sebenarnya hanya latensi yang tidak Anda perhitungkan.

Penanganan Kesalahan

Perilaku default SuperAgent berbeda dari kebanyakan klien, dan hal ini penting dalam konteks ini.

Dokumentasinya menegaskan: "Secara default, SuperAgent menganggap respons 4xx dan 5xx (serta respons 3xx yang tidak ditangani) sebagai kesalahan". Dokumentasi tersebut menambahkan bahwa "informasi status ini akan tersedia melalui err.status", dan bahwa kesalahan semacam itu "juga berisi bidang err.response".

Jadi, kegagalan otentikasi proxy muncul sebagai penolakan, bukan sebagai respons:

try {
  const res = await request.get(url).agent(agent).timeout({ deadline: 30000 });
  return res.body;
} catch (err) {
  if (err.status === 407) throw new Error("Proxy rejected credentials");
  if (err.status === 401) throw new Error("Target requires authentication");
  if (!err.status) throw new Error(`Network error: ${err.code} ${err.message}`);
  throw err;
}

Perbedaan antara 407 dan 401 adalah hal yang perlu diperhatikan. Kode 407 berarti proxy telah menghentikan Anda dan target tidak pernah tercapai; kode 401 berarti proxy berfungsi dan target meminta kredensial. Pihak yang berbeda, solusi yang berbeda, dan keduanya sangat mudah tertukar ketika keduanya muncul sebagai kesalahan yang dilemparkan.

Kesalahan tanpa err.status berarti tidak ada respons HTTP yang diterima sama sekali, yang mengindikasikan masalah koneksi, bukan masalah otentikasi. ECONNREFUSED berarti tidak ada yang mendengarkan di alamat proxy; ETIMEDOUT berarti paket-paket hilang.

Untuk memperlakukan beberapa status kesalahan sebagai keberhasilan — mengartikan 404 sebagai data, bukan kegagalan — gunakan .ok():

.ok(res => res.status < 500)

Upaya Ulang, Lakukan dengan Hati-hati

SuperAgent memiliki fitur upaya ulang bawaan, dengan batasan yang tercantum dalam dokumentasi dan sebaiknya dipatuhi.

const res = await request.get(url).agent(agent).retry(2);

Dokumentasi tersebut menjelaskan bahwa .retry() "akan secara otomatis mencoba ulang permintaan, jika permintaan tersebut gagal karena masalah sementara atau mungkin disebabkan oleh koneksi internet yang tidak stabil", dengan menerima jumlah percobaan ulang opsional (default 1) dan callback yang dipanggil "sebelum setiap percobaan ulang". Fungsi callback "dapat mengembaliktrue, ataufalse untuk mengontrol apakah permintaan harus dicoba ulang (namun jumlah maksimum percobaan ulang selalu diterapkan)".

Dan batasan tersebut, yang dinyatakan secara jelas dalam dokumentasi: gunakan .retry() "hanya untuk permintaan yang idempoten".

Melalui proxy, hal ini lebih penting dari biasanya, karena alasan tertentu. Timeout bukanlah bukti kegagalan — permintaan mungkin telah mencapai tujuan dan berhasil, sementara responsnya hilang dalam perjalanan kembali. Ada hop tambahan di mana hal itu bisa terjadi. Melakukan percobaan ulang POST dalam situasi tersebut dapat menyebabkan duplikasi penulisan, dan tidak ada konfigurasi percobaan ulang apa pun yang dapat menjamin keamanan hal tersebut. Jika operasi tersebut penting, gunakan kunci idempotensi jika API menyediakannya.

Callback juga merupakan tempat yang tepat untuk menghindari pengulangan upaya saat terjadi kegagalan otentikasi, karena kode status 407 akibat kredensial yang salah akan menghasilkan kode status 407 pada setiap upaya:

.retry(3, (err, res) => {
  if (res?.status === 407 || res?.status === 401) return false;
  return true;
})

Wrapper yang Layak Dibuat

Rantai (chaining) SuperAgent dilakukan per permintaan, yang berarti konfigurasi proxy mudah terlupakan pada panggilan yang paling penting. Dengan membungkus (wrapping) proses pembuatan permintaan, masalah tersebut teratasi dan Anda memiliki tempat untuk menempatkan sisa pengaturan default.

import request from "superagent";
import { ProxyAgent } from "proxy-agent";

const agent = process.env.PROXY_URL ? new ProxyAgent(process.env.PROXY_URL) : undefined;

const UA = "AcmeBot/1.0 (+https://acme.example.com/bot)";

function req(method, url) {
  const r = request[method](url)
    .set("User-Agent", UA)
    .timeout({ response: 15000, deadline: 60000 })
    .retry(2, (err, res) => {
      if (res?.status === 407 || res?.status === 401) return false;
      if (res?.status === 429) return false;   // honour the rate limit instead
      return true;
    });
  return agent ? r.agent(agent) : r;
}

export const get = url => req("get", url);
export const post = url => req("post", url);

export async function verifyExit() {
  const res = await get("https://api.ipify.org?format=json");
  console.log(`Exit address: ${res.body.ip}`);
  return res.body.ip;
}

Lima pilihan di sana disengaja.

Proxy bersifat opsional dan diambil dari lingkungan. Tanpa PROXY_URL, agen menggunakan undefined dan permintaan dikirim langsung, sehingga pengembangan lokal dan produksi berperilaku dapat diprediksi tanpa perlu membuat cabang dalam kode aplikasi Anda. Tidak ada kredensial yang muncul di kode sumber.

ProxyAgent tanpa argumen konstruktor akan dibaca sebagai http_proxy dan sejenisnya jika Anda lebih memilih konfigurasi berbasis lingkungan; meneruskan URL secara eksplisit membuat sumber kebenaran menjadi jelas, yang biasanya lebih berharga.

User agent-nya jujur dan menyertakan URL kontak. Hal ini tidak memerlukan biaya apa pun dan mengubah apa yang terjadi ketika operator situs menyadari keberadaan Anda.

Upaya ulang mengecualikan status di mana upaya ulang tidak berguna atau tidak sopan. Kode status 407 akibat kredensial yang salah akan tetap 407 setiap kali; kode status 429 adalah instruksi untuk memperlambat, dan melakukan upaya ulang ke status tersebut akan mengubah batas sementara menjadi batas yang lebih lama.

Fungsi verifyExit() diekspor dan dipanggil saat startup. Enam baris kode yang mengubah proxy yang dilewati secara diam-diam menjadi entri dalam log — yang merupakan tema tunggal yang berulang dalam kerja proxy di setiap klien, dan satu-satunya hal yang tidak akan dilakukan oleh perpustakaan mana pun untuk Anda.

.connect() Bukanlah Proksi

Perlu diperhatikan karena tampaknya seperti proksi, padahal sebenarnya bukan.

SuperAgent menawarkan metode .connect() yang, menurut dokumentasinya, memungkinkan pengguna "mengabaikan resolusi DNS dan mengarahkan semua permintaan ke alamat IP tertentu". Metode ini mendukung pemetaan, termasuk opsi cadangan *:

const res = await request.get("http://redir.example.com:555")
  .connect({
    "redir.example.com": "127.0.0.1",
    "www.example.com": false,
    "mapped.example.com": { host: "127.0.0.1", port: 8080 },
    "*": "proxy.example.com",
  });

Dokumentasi tersebut menyebutkan bahwa "permintaan akan tetap mempertahankan header Host dengan nilai aslinya", dan bahwa .connect(undefined) menonaktifkan fitur ini.

Ini adalah pengalihan host, bukan proksi. Fitur ini mengubah alamat tujuan koneksi sambil membiarkan permintaan tetap tidak berubah — tidak ada terowongan CONNECT, tidak ada protokol proksi, dan tidak ada otentikasi proksi. Fitur ini disediakan untuk pengujian, dan dokumentasinya menempatkannya di bawah "Pengujian di localhost" dengan alasan yang jelas.

Baris "*": "proxy.example.com" dalam contoh resmi adalah sumber kebingungan. Gunakan .connect() untuk mengarahkan permintaan ke server pengujian lokal; gunakan agen (agent) untuk proxy yang sebenarnya.

Pertanyaan Terkait

Bagaimana cara menggunakan proxy dengan SuperAgent?

Berikan agen proxy ke .agent(): buat HttpsProxyAgent atau SocksProxyAgent dengan URL proxy Anda, lalu sertakan dalam permintaan. Sebagai alternatif, gunakan ekstensi superagent-proxy, yang menambahkan metode .proxy(uri) — meskipun paket tersebut belum dirilis sejak 2021.

Apa perbedaan antara .agent() dengan dan tanpa argumen?

Tanpa argumen, metode ini membuat salinan SuperAgent yang menyimpan cookie dengan file jar dan opsi defaultnya sendiri. Dengan argumen, metode ini mengatur properti http.Agent Node untuk permintaan tersebut, yang merupakan cara penerapan dukungan proxy. Nama yang sama ini memang menimbulkan kebingungan.

Apakah superagent-proxy masih dipelihara?

Paket ini tidak dihentikan, tetapi versi 3.0.0 dirilis pada September 2021, sementara dependensi dasarnya, proxy-agent, terus dirilis — yang terbaru pada Juni 2026. Untuk kode baru, menggunakan agen proxy secara langsung menghindari penggunaan wrapper yang sudah usang dengan biaya satu baris kode tambahan.

Mengapa proxy SuperAgent saya tidak berfungsi?

Penyebab paling umum adalah panggilan ke .agent() tanpa argumen, yang akan membuat "cookie jar" alih-alih mengatur proxy. Pastikan juga agen diterapkan pada permintaan yang tepat, karena rantai SuperAgent berlaku per panggilan. Verifikasi dengan meminta layanan yang melaporkan alamat Anda — proxy yang dilewati tidak akan menghasilkan kesalahan.

Apakah SuperAgent menghormati variabel lingkungan HTTP_PROXY?

Tidak secara otomatis. Paket proxy-agent memang membaca http_proxy, https_proxy, dan no_proxy, jadi dengan membuat ProxyAgent() tanpa argumen dan meneruskannya ke .agent(), Anda akan mendapatkan perilaku yang dipengaruhi oleh variabel lingkungan.

Bagaimana cara mengatur batas waktu (timeout) untuk permintaan yang diproksi?

Gunakan kedua pengaturan ini: .timeout({ response: 15000, deadline: 60000 }). Batas waktu respons membatasi waktu tunggu untuk byte pertama, sedangkan batas waktu keseluruhan membatasi seluruh permintaan. Tentukan nilainya berdasarkan pengukuran yang diambil melalui proxy, karena titik keluar (exit) perumahan menambah latensi nyata pada fase DNS, koneksi, dan TLS.

Bagaimana cara membedakan kesalahan proxy dari kesalahan target?

Berdasarkan status. SuperAgent menganggap kode 4xx dan 5xx sebagai kesalahan, jadi tangkap dan baca err.status — kode 407 berarti proxy menolak permintaan Anda dan target tidak pernah tercapai, sedangkan kode 401 berarti proxy berfungsi dan target meminta kredensial. Jika tidak ada respons "err.status" sama sekali, berarti tidak ada respons HTTP yang diterima.

Bisakah saya menggunakan .connect() sebagai proxy?

Tidak. Fungsi ini mengalihkan permintaan ke alamat IP tertentu sambil mempertahankan header Host asli, yang merupakan pemetaan host untuk pengujian, bukan proxy. Tidak ada terowongan, tidak ada protokol proxy, dan tidak ada otentikasi. Gunakan agen untuk proxy yang sesungguhnya.

Kesimpulan

SuperAgent tidak memiliki opsi proxy bawaan, jadi pilihannya adalah menggunakan agen atau ekstensi — dan agen merupakan pilihan default yang lebih baik, karena paket-paket yang dikelola lah yang sebenarnya melakukan pekerjaan tersebut dalam kedua kasus tersebut.

Istilah-istilah yang digunakan adalah jebakan utamanya. Perintah .agent() tanpa argumen akan menampilkan daftar cookie; sedangkan .agent(something) akan mengatur agen HTTP. Banyak orang mengonfigurasi yang pertama, melihat permintaan berhasil, lalu menyimpulkan bahwa proxy berfungsi. Tidak ada yang mengoreksi kesalahpahaman ini, karena proxy yang dilewati (bypassed) secara definisi akan gagal tanpa pemberitahuan.

Hal ini menjadikan verifikasi sebagai kebiasaan yang layak dikembangkan. Kirim permintaan ke layanan yang melaporkan alamat Anda, baik dengan maupun tanpa agen, dan pastikan jawabannya berubah. Untuk pekerjaan yang ditargetkan secara geografis, lakukan verifikasi lebih lanjut dan pastikan bahwa konten yang berbeda secara regional benar-benar berbeda — alamat hanyalah bagian yang mudah dan paling tidak informatif.

Kemudian atur kedua batas waktu (timeout), buat percabangan berdasarkan status err.status sehingga kode status 407 dan 401 menghasilkan pesan yang berbeda, dan hindari penggunaan .retry() pada apa pun yang tidak bersifat idempoten. Melalui proxy, terdapat lompatan tambahan di mana permintaan yang berhasil dapat kehilangan responsnya, dan upaya ulang dalam situasi tersebut merupakan duplikasi, bukan pemulihan.