Got proxy: gắn agent cho Got 14 trong Node.js và kiểm thử
Got proxy là cách cho thư viện Got trong Node.js gửi request qua một máy trung gian thay vì đi thẳng ra Internet. Got không có tùy chọn proxy riêng, mọi thứ xoay quanh tham số agent. ProxyVN chạy Got 14.6.6 qua proxy HTTP và SOCKS5 tự dựng, 15 ca thử, ghi nguyên văn từng lỗi để anh em gắn đúng và sửa đúng chỗ.
Got proxy khác Axios và fetch ở điểm nào
Got không đọc biến môi trường proxy

Got không đọc HTTP_PROXY
Điều đầu tiên anh em cần biết là Got không tự đọc HTTP_PROXY hay HTTPS_PROXY. Trong lần thử, mình đặt biến HTTP_PROXY trỏ về proxy cục bộ rồi gọi Got không kèm agent. Kết quả là lỗi getaddrinfo ENOTFOUND shop.test, nghĩa là Got tự phân giải tên miền và đi thẳng, không hề ghé proxy.
Chi tiết này làm nhiều người mất thời gian. Họ quen với curl, pip hay npm, những công cụ đọc biến môi trường mặc định. Với Got, biến môi trường chỉ có tác dụng khi anh em tự đọc nó trong mã rồi truyền vào agent, hoặc khi dùng thêm một gói cài proxy toàn cục như global-agent.
Muốn Got đi qua proxy thì phải truyền agent, không có đường tắt nào khác. Phần còn lại của bài đều xoay quanh việc chọn agent nào, gắn vào đâu và kiểm ra sao.
Agent là gì trong Got
Agent là đối tượng của Node.js chịu trách nhiệm mở và giữ kết nối TCP. Khi anh em truyền agent của một gói proxy, agent đó sẽ mở kết nối tới proxy thay vì tới website, rồi xin proxy nối tiếp tới đích. Got chỉ việc gửi request trên đường kết nối agent trả về.
Got nhận agent theo dạng một đối tượng có ba khóa http, https và http2. Khóa http dùng cho URL bắt đầu bằng http://, khóa https dùng cho URL https://. Mình đã thử truyền chỉ khóa https rồi gọi một URL http, request lại đi thẳng và báo ENOTFOUND. Thiếu khóa nào thì loại URL đó không có proxy.
Trang mẹo dùng Got trên GitHub gợi ý hai gói chính là hpagent và bộ agent của Apify, đồng thời nhắc rằng gói tunnel đã ngừng bảo trì. Trang này cũng nói rõ client HTTP/2 tích hợp trong Got không hỗ trợ proxy. Nếu anh em bật http2: true, đừng mong agent proxy có tác dụng với các kết nối HTTP/2.
Ranh giới với bài Axios và fetch
Axios có tùy chọn proxy riêng trong cấu hình request và có đọc biến môi trường theo mặc định. Fetch tích hợp trong Node dựa trên Undici và dùng dispatcher thay cho agent. Hai cơ chế đó đã có hướng dẫn trong bài Axios proxy và bài Node.js fetch proxy.
Bài này chỉ nói về Got: đúng phiên bản ESM, đúng kiểu agent, cách mở rộng instance bằng extend và các tùy chọn retry, timeout ảnh hưởng thế nào khi đi qua proxy. Nếu dự án của anh em không dùng Got, hai bài trên sẽ hợp hơn.
Chuẩn bị môi trường cho Got proxy
Phiên bản và kiểu module
Got từ bản 12 trở đi là gói ESM thuần. Anh em không thể gọi require('got') trong tệp CommonJS như thời bản 11. Trang mẹo của Got cũng ghi riêng cho Electron rằng nếu môi trường chưa hỗ trợ ESM thì phải dùng Got 11.
Lab của mình dùng Node 24.20 trên Windows 10, Got 14.6.6, hpagent 1.2.0 và socks-proxy-agent 8.0.5. Tệp thử đặt đuôi .mjs để Node đọc theo ESM. Nếu dự án dùng package.json với "type": "module" thì tệp .js cũng được.
mkdir got-proxy-lab && cd got-proxy-lab
npm init -y
npm i got@14.6.6 hpagent@1.2.0 socks-proxy-agent@8.0.5
Khóa phiên bản như trên giúp kết quả lặp lại được. Khi nâng Got lên bản lớn mới, đọc lại mục breaking changes rồi chạy lại bộ ca thử trước khi đưa lên máy chủ.
Dựng proxy thử để chứng minh đường đi
Mình không thử thẳng với proxy thương mại ngay từ đầu. Thay vào đó là một chương trình Python nhỏ nghe ba cổng: 8911 là website thử, 8912 là proxy HTTP yêu cầu tài khoản user1 với mật khẩu p@ss#2026, 8913 là proxy SOCKS5 cùng tài khoản. Mọi request tới proxy đều được ghi vào một tệp nhật ký JSON.
Website thử có tên shop.test. Tên này chỉ phân giải được bên trong proxy, vì proxy tự trỏ mọi tên đuôi .test về máy cục bộ. Request nào lỡ đi thẳng sẽ báo ENOTFOUND ngay. Request nào đi qua proxy sẽ trả về JSON có đường dẫn và User-Agent. Nhờ vậy mình nhìn kết quả là biết đường đi, không cần đoán.
Cách dựng này hữu ích cho cả dự án thật. Trước khi trả tiền cho một gói proxy, anh em có thể kiểm mã Got của mình với proxy cục bộ, chắc rằng mọi request đều đi đúng đường rồi mới đổi sang địa chỉ thật.
Tách thông tin proxy ra biến môi trường
Chuỗi proxy chứa mật khẩu, không nên nằm trong mã. Mình đặt nó vào biến PROXY_URL rồi đọc trong mã. Dạng chuỗi là http://tên:mật-khẩu@máy:cổng cho proxy HTTP và socks5h://tên:mật-khẩu@máy:cổng cho SOCKS5.
Nếu nhà cung cấp gửi proxy dạng ip:port:user:pass, cần đổi lại trước khi dùng. Bài định dạng proxy có bảng chuyển đổi qua lại giữa các kiểu viết. Một chuỗi sai định dạng sẽ tạo ra những lỗi rất khó hiểu, phần sau có ví dụ cụ thể.
Cấu hình Got proxy tối thiểu với hpagent
Đoạn mã chạy được
Đoạn dưới đây là cấu hình nhỏ nhất mình đã chạy thật. Nó tạo hai agent từ cùng một chuỗi proxy, gắn vào cả hai khóa http và https rồi gọi một trang thử.
import got from 'got';
import {HttpProxyAgent, HttpsProxyAgent} from 'hpagent';
const proxy = process.env.PROXY_URL;
const agent = {
http: new HttpProxyAgent({proxy, keepAlive: true}),
https: new HttpsProxyAgent({proxy, keepAlive: true})
};
const data = await got('http://shop.test:8911/c', {agent, retry: {limit: 0}}).json();
console.log(data);
Kết quả trả về có path là /c và ua là got (https://github.com/sindresorhus/got). Nhật ký proxy ghi một dòng CONNECT tới shop.test:8911 với tài khoản user1, auth_ok là true. Đây là bằng chứng request đã đi qua proxy và proxy nhận đúng tài khoản.
hpagent mở đường hầm cho cả URL http
Một điều mình không đoán trước: với URL http://, hpagent vẫn gửi lệnh CONNECT chứ không gửi request dạng địa chỉ đầy đủ như curl hay trình duyệt. Nhật ký cho thấy mọi request trong lab đều là CONNECT, kể cả GET và POST tới URL http.
Với đa số proxy thương mại, chuyện này không gây lỗi vì proxy cho phép CONNECT tới cổng 80 và 443. Nhưng một số proxy công ty chặn CONNECT tới cổng khác 443. Khi đó request http qua hpagent sẽ bị từ chối dù trình duyệt vẫn chạy được. Nếu gặp lỗi kiểu này, hỏi quản trị mạng xem proxy có giới hạn cổng cho CONNECT hay không.
Một hệ quả nữa là proxy không đọc được nội dung request http, vì nó chỉ thấy luồng dữ liệu đi qua đường hầm. Proxy thử của mình gắn tiêu đề X-Lab-Via vào request dạng địa chỉ đầy đủ, nhưng trong lab Got trường via luôn trống. Đó là dấu hiệu nhận ra đường hầm.
Giải thích từng tùy chọn
Mỗi tùy chọn trong đoạn mã trên có một vai trò riêng, hiểu rõ giúp anh em biết chỗ nào cần chỉnh khi chạy tải lớn.
- proxy: chuỗi URL của proxy, có thể kèm tài khoản. hpagent tự tách tên và mật khẩu, tự tạo tiêu đề Proxy-Authorization kiểu Basic.
- keepAlive: giữ kết nối tới proxy để dùng lại cho request sau. Theo trang mẹo của Got, đây là điểm hpagent hơn gói tunnel cũ.
- agent.http và agent.https: phải có cả hai nếu dự án gọi cả hai loại URL. Thiếu khóa nào thì URL loại đó đi thẳng.
- retry.limit: đặt 0 trong lúc thử để thấy lỗi gốc, tránh Got thử lại che mất nguyên nhân.
Trang mẹo của Got còn đưa ví dụ với maxSockets, maxFreeSockets và scheduling: 'lifo'. Các tùy chọn này giới hạn số kết nối song song tới proxy. Khi gói proxy giới hạn số luồng, đặt maxSockets bằng hoặc thấp hơn hạn mức đó để tránh bị từ chối giữa chừng.
Got proxy với tài khoản có ký tự đặc biệt
Lỗi lạ khi mật khẩu có @ và #
Mật khẩu thử của mình là p@ss#2026. Khi đưa nguyên chuỗi http://user1:p@ss#[email protected]:8912 vào hpagent, Got báo getaddrinfo ENOTFOUND ss. Tên máy ss không có ở đâu trong cấu hình, nó là phần bị tách sai từ mật khẩu.
Lý do nằm ở cách đọc URL. Ký tự @ đầu tiên được coi là chỗ ngăn tài khoản với tên máy, còn # mở đầu phần fragment. Vì vậy phần sau @ bị hiểu thành máy ss, và mọi thứ sau # bị bỏ đi. Kiểu lỗi này rất dễ nhầm là proxy chết hoặc DNS hỏng.
Thấy tên máy lạ trong lỗi ENOTFOUND, hãy kiểm mật khẩu trước khi kiểm mạng. Đây là bài học rút ra từ lần chạy này và đúng với hầu hết thư viện nhận proxy dạng URL.
Mã hóa phần trăm đúng cách

Mã hóa @ thành %40, # thành %23
Cách sửa là mã hóa tên và mật khẩu theo quy tắc phần trăm của chuẩn URI RFC 3986. Với mật khẩu trên, chuỗi đúng là http://user1:p%40ss%[email protected]:8912. Mình chạy lại với chuỗi này, proxy ghi nhận user1 và auth_ok là true.
Trong Node, cách an toàn là để mã tự mã hóa, không bắt người cấu hình phải nhớ quy tắc.
function proxyUrl({scheme = 'http', host, port, user, pass}) {
const auth = user ? `${encodeURIComponent(user)}:${encodeURIComponent(pass)}@` : '';
return `${scheme}://${auth}${host}:${port}`;
}
const proxy = proxyUrl({
host: process.env.PROXY_HOST,
port: process.env.PROXY_PORT,
user: process.env.PROXY_USER,
pass: process.env.PROXY_PASS
});
Tách bốn biến riêng như trên cũng tiện hơn khi đổi gói proxy. Người vận hành chỉ thay giá trị, không phải ghép chuỗi bằng tay.
Sai mật khẩu thì Got báo gì
Với mật khẩu sai, Got trả lỗi RequestError có mã ERR_GOT_REQUEST_ERROR và thông điệp Bad response: 407. Thông điệp này đến từ hpagent khi proxy trả 407 cho lệnh CONNECT. Got không coi đó là HTTPError có statusCode vì request chưa tới được website.
Điểm này quan trọng khi viết mã xử lý lỗi. Nếu anh em chỉ bắt error.response?.statusCode === 407 thì sẽ không bao giờ bắt được lỗi này. Cách chắc hơn là kiểm error.message có chứa 407 khi error.code là ERR_GOT_REQUEST_ERROR. Bài sửa lỗi 407 Proxy Authentication Required có danh sách nguyên nhân phía nhà cung cấp như sai tài khoản, hết hạn gói hay chưa thêm IP vào danh sách cho phép.
Gắn Got proxy vào instance bằng extend
Tạo một client dùng chung
Trong dự án thật, không ai truyền agent vào từng lời gọi got(). Cách gọn là tạo một instance bằng got.extend với agent, timeout, retry và hooks đặt sẵn, rồi dùng instance đó ở mọi nơi.
import got from 'got';
import {HttpProxyAgent, HttpsProxyAgent} from 'hpagent';
const proxy = process.env.PROXY_URL;
export const client = got.extend({
agent: {
http: new HttpProxyAgent({proxy, keepAlive: true, maxSockets: 10}),
https: new HttpsProxyAgent({proxy, keepAlive: true, maxSockets: 10})
},
timeout: {lookup: 2000, connect: 3000, request: 8000},
retry: {limit: 2, methods: ['GET']},
hooks: {
beforeRetry: [(error, count) => console.log('retry', count, error.code)],
beforeRedirect: [(options, response) => console.log('redirect', response.statusCode, String(options.url))]
}
});
Mình dùng instance này cho các ca GET, POST, redirect, timeout và lỗi 503 ở phần sau. Tất cả đều đi qua proxy, nhật ký ghi đủ số lệnh CONNECT tương ứng.
Agent nằm ở instance, không phải ở request
Khi agent nằm trong extend, mọi request của instance dùng chung một bể kết nối tới proxy. Điều này tốt cho tốc độ vì không phải bắt tay lại với proxy mỗi lần. Nhưng nó cũng có nghĩa là mọi request của instance đi ra cùng một proxy.
Nếu anh em cần mỗi tài khoản mạng xã hội hay mỗi luồng crawl một IP riêng, hãy tạo một instance riêng cho mỗi proxy. Đừng chia sẻ agent giữa các instance có proxy khác nhau. Mình khuyên lưu các instance trong một Map theo khóa proxy để dùng lại, tránh tạo agent mới mỗi request rồi để rò rỉ socket.
Đổi proxy giữa chừng
Got cho phép truyền agent khác ở từng lời gọi, giá trị đó sẽ đè lên agent của instance. Cách này dùng được khi thỉnh thoảng cần một request đi qua proxy khác, ví dụ kiểm giá ở một vùng khác.
Với proxy xoay theo phiên, nhà cung cấp thường đổi IP bằng cách đổi tên người dùng hoặc gọi một đường dẫn đổi IP. Khi tên người dùng đổi, anh em cần agent mới vì agent cũ đã gắn tiêu đề xác thực cũ vào kết nối giữ sẵn. Bài API đổi IP proxy xoay nói rõ cách gọi đổi IP và thời điểm nên đổi.
Got proxy với SOCKS5
Dùng socks-proxy-agent
hpagent chỉ làm việc với proxy HTTP. Khi gói proxy chỉ có cổng SOCKS5, anh em dùng socks-proxy-agent. Một agent của gói này dùng được cho cả http và https.
import got from 'got';
import {SocksProxyAgent} from 'socks-proxy-agent';
const agent = new SocksProxyAgent(process.env.SOCKS_URL);
const data = await got('http://shop.test:8911/s', {agent: {http: agent, https: agent}}).json();
Với chuỗi socks5h://user1:p%40ss%[email protected]:8913, request qua proxy và nhật ký SOCKS ghi lệnh CONNECT tới tên miền shop.test, kiểu địa chỉ là domain.
socks5 và socks5h khác nhau thật
Mình chạy cùng đoạn mã với tiền tố socks5:// thay vì socks5h://. Lần này Got báo getaddrinfo ENOTFOUND shop.test, proxy SOCKS không nhận được kết nối nào. Với socks5://, socks-proxy-agent tự phân giải tên miền trên máy rồi gửi IP cho proxy. Với socks5h://, tên miền được gửi nguyên cho proxy phân giải.
Trong thực tế, khác biệt này ảnh hưởng tới rò rỉ DNS. Nếu dùng socks5://, máy của anh em vẫn hỏi DNS cục bộ cho mọi tên miền, nhà mạng thấy được danh sách website dù dữ liệu đi qua proxy. Bài DNS leak khi dùng proxy giải thích kỹ hơn. Với crawler, dùng socks5h:// để proxy phân giải tên miền.
Chọn HTTP hay SOCKS5 cho Got
Với Got, proxy HTTP qua hpagent thường là lựa chọn đơn giản nhất, vì hpagent giữ kết nối tốt và lỗi 407 rõ ràng. SOCKS5 hợp khi gói proxy chỉ mở cổng SOCKS hoặc khi cần đi qua các giao thức không phải HTTP trong cùng ứng dụng.
Bảng dưới tóm tắt những gì mình đã thử trong lab, không phải bảng tính năng chính thức của các gói.
Ca thử |
Agent |
Kết quả trong lab |
|---|---|---|
Không agent, có HTTP_PROXY |
Không |
ENOTFOUND, đi thẳng |
HTTP có tài khoản đã mã hóa |
hpagent |
Qua proxy, CONNECT, auth đúng |
Mật khẩu chưa mã hóa |
hpagent |
ENOTFOUND ss |
Sai mật khẩu |
hpagent |
ERR_GOT_REQUEST_ERROR, Bad response: 407 |
Chỉ có khóa https, gọi URL http |
hpagent |
ENOTFOUND, đi thẳng |
socks5:// |
socks-proxy-agent |
ENOTFOUND, phân giải cục bộ |
socks5h:// |
socks-proxy-agent |
Qua proxy, gửi tên miền |
Bảng này cho thấy phần lớn lỗi Got proxy là lỗi cấu hình phía mã, không phải lỗi mạng. Chạy đủ bảy ca này một lần là anh em loại được gần hết nguyên nhân trước khi liên hệ nhà cung cấp.
Chạy đối chứng Got proxy: POST, redirect, timeout và retry

Timeout và retry khi đi qua proxy
POST và JSON
Mình gửi POST với tùy chọn json: {sku: 'A1'} qua instance ở trên. Website thử nhận đúng thân request {"sku":"A1"} và trả lại method POST. Nhật ký proxy ghi một CONNECT, nghĩa là POST đi trong đường hầm như GET.
Một điều cần nhớ: theo tài liệu retry của Got, mặc định Got không thử lại POST. Danh sách phương thức thử lại gồm GET, PUT, HEAD, DELETE, OPTIONS, TRACE và QUERY. Trong lab, instance của mình còn giới hạn chỉ GET, nên POST chỉ gửi một lần dù gặp lỗi. Đây là hành vi đúng, vì gửi lại một đơn hàng hay một biểu mẫu có thể tạo bản ghi trùng.
Redirect đi qua proxy
Đường dẫn /redir của website thử trả 302 chuyển sang /after-redirect. Hook beforeRedirect in ra redirect 302 http://shop.test:8911/after-redirect, response cuối có mã 200. Thuộc tính redirectUrls của response chứa đúng một địa chỉ.
Request sau redirect vẫn đi qua proxy vì cùng instance và cùng agent. Nếu redirect chuyển từ http sang https, Got sẽ dùng khóa https của agent. Đó là thêm một lý do phải khai báo đủ cả hai khóa. Thiếu khóa https, request sau redirect sẽ đi thẳng mà không có lỗi nào báo cho anh em biết.
Timeout theo từng giai đoạn
Tài liệu timeout của Got ghi rõ mặc định không có timeout nào. Với proxy, đây là rủi ro lớn: một proxy treo có thể giữ request mãi mãi. Got chia timeout theo giai đoạn: lookup, connect, secureConnect, socket, send, response, read và request.
Khi đi qua agent proxy, các giai đoạn lookup và connect đo việc kết nối tới proxy, không phải tới website. Vì thế mình đặt lookup 2 giây, connect 3 giây và request 8 giây cho cả vòng đời request. Timeout request bao gồm cả thời gian redirect, theo tài liệu.
Trong ca thử /slow, website chờ 5 giây trước khi trả lời. Với timeout request 2 giây và retry 1 lần, Got in retry 1 ETIMEDOUT rồi báo TimeoutError với thông điệp Timeout awaiting 'request' for 2000ms. Thông điệp này cho biết giai đoạn nào quá hạn, rất có ích khi đoán xem chậm ở proxy hay ở website.
Got không đặt timeout mặc định. Khi đi qua proxy, hãy luôn đặt ít nhất timeout request, nếu không một proxy treo sẽ giữ tiến trình của anh em vô thời hạn.
Retry với lỗi mạng và mã 503
Danh sách mã lỗi được thử lại mặc định gồm ETIMEDOUT, ECONNRESET, ECONNREFUSED, ENOTFOUND, EAI_AGAIN và vài mã khác. Danh sách mã HTTP gồm 408, 413, 429, 500, 502, 503, 504, 521, 522 và 524. Mặc định giới hạn là 2 lần.
Khi trỏ agent vào cổng 8999 không có proxy, Got in retry 1 ECONNREFUSED rồi báo connect ECONNREFUSED 127.0.0.1:8999. Địa chỉ trong lỗi là địa chỉ proxy, không phải website. Đây là cách nhận ra proxy không mở cổng hoặc sai cổng. Với đường dẫn /status/503, Got thử lại 2 lần rồi báo HTTPError với mã 503.
Thử lại với 503 có lợi khi website quá tải tạm thời. Nhưng nếu 503 đến từ proxy vì gói đã hết hạn mức, thử lại chỉ làm tốn thời gian. Bài lỗi 503 Service Unavailable giúp phân biệt 503 của website với 503 của proxy.
Đọc lỗi Got proxy theo thông điệp
Bảng tra nhanh
Phần này gom các thông điệp mình đã thấy trong lab thành bảng tra. Cột bên phải là chỗ cần kiểm trước tiên.
Thông điệp lỗi |
Nghĩa |
Kiểm trước |
|---|---|---|
getaddrinfo ENOTFOUND tên-website |
Request đi thẳng, không qua proxy |
Đã truyền agent chưa, có đủ khóa http và https không |
getaddrinfo ENOTFOUND tên-lạ |
Chuỗi proxy bị tách sai |
Mật khẩu có @, #, :, / chưa mã hóa |
Bad response: 407 |
Proxy từ chối tài khoản |
Tên, mật khẩu, IP cho phép |
connect ECONNREFUSED địa-chỉ-proxy |
Proxy không mở cổng |
Máy, cổng, tường lửa |
Timeout awaiting 'connect' |
Không bắt tay được với proxy |
Mạng tới proxy, proxy quá tải |
Timeout awaiting 'request' |
Cả vòng request quá hạn |
Website chậm hay proxy chậm |
HTTPError 403, 429 |
Website từ chối |
IP bị chặn, tần suất quá cao |
Một lưu ý về lỗi ENOTFOUND: nếu tên trong lỗi là tên website, gần như chắc request chưa qua proxy. Nếu là tên của proxy, DNS máy không phân giải được máy proxy. Nếu là một chuỗi lạ, chuỗi proxy đã hỏng.
Ghi log đủ để chẩn đoán
Khi lỗi xảy ra trên máy chủ, anh em không thể chạy lại từng ca. Vì vậy mình khuyên ghi lại năm thông tin cho mỗi request lỗi: error.code, error.name, error.message, error.timings nếu có, và tên proxy đã dùng nhưng đã che mật khẩu.
try {
await client('https://example.com/');
} catch (error) {
console.error(JSON.stringify({
code: error.code,
name: error.name,
message: error.message,
status: error.response?.statusCode,
proxy: process.env.PROXY_HOST,
phases: error.timings?.phases
}));
}
Đừng in nguyên options hay chuỗi proxy, vì chúng chứa mật khẩu. Thuộc tính timings.phases cho biết thời gian từng giai đoạn, giúp tách chậm do proxy hay do website. Bài lỗi kết nối bị từ chối có thêm các nguyên nhân phía mạng nếu ECONNREFUSED lặp lại.
Khi proxy báo 502 hoặc ngắt kết nối
Nếu proxy không kết nối được tới website, nó thường trả 502 cho lệnh CONNECT. hpagent sẽ báo Bad response: 502, cùng kiểu với 407. Đọc mã số trong thông điệp để biết lỗi ở bước xác thực hay bước nối tới đích.
Lỗi ECONNRESET giữa chừng thường do proxy cắt kết nối khi vượt hạn mức luồng hoặc khi IP xoay. Got thử lại ECONNRESET cho GET theo mặc định. Nếu lỗi này dày đặc, giảm maxSockets của agent xuống trước khi tăng số lần thử lại.
Đưa Got proxy vào dự án thật
Cấu trúc tệp gợi ý
Khi đã qua các ca thử, mình gom cấu hình vào một tệp riêng để các phần khác của dự án chỉ nhập client.
- net/proxy.js: đọc biến môi trường, mã hóa tài khoản, tạo agent HTTP hoặc SOCKS theo tiền tố.
- net/client.js: gọi got.extend với agent, timeout, retry và hooks ghi log.
- test/proxy.test.js: một ca gọi trang kiểm IP và so sánh với IP proxy mong đợi.
Tách như vậy giúp đổi nhà cung cấp hay đổi loại proxy mà không đụng tới mã crawl. Ca thử kiểm IP nên chạy đầu tiên trong CI, nếu IP ra trùng IP máy chủ thì dừng ngay.
Bỏ qua proxy cho địa chỉ nội bộ
Got không có tùy chọn no_proxy. Khi dự án gọi cả API nội bộ và website bên ngoài, anh em phải tự quyết request nào dùng agent. Cách đơn giản là hai instance: một instance có proxy cho website bên ngoài, một instance không agent cho localhost và tên miền nội bộ.
Nếu muốn một instance tự chọn, có thể dùng hook beforeRequest kiểm tên máy rồi gán options.agent. Tuy vậy, hai instance riêng dễ đọc và dễ kiểm hơn. Bài no_proxy là gì giải thích quy ước bỏ qua proxy mà nhiều công cụ khác dùng, anh em có thể áp lại cho danh sách của mình.
Chọn loại proxy cho việc gọi bằng Got
Got hay được dùng để gọi API và crawl trang tĩnh. Với API cần IP cố định để nhà cung cấp API cho phép, proxy tĩnh hợp hơn proxy xoay. Với crawl nhiều trang, proxy xoay giúp chia tải nhưng cần agent mới khi đổi phiên.
ProxyVN có proxy dân cư tĩnh, datacenter và proxy xoay, đều cấp tài khoản user và mật khẩu, hỗ trợ HTTP và SOCKS5. Nếu cần một gói để chạy đúng cấu hình đã thử ở trên, anh em có thể mua proxy tại trang chủ ProxyVN rồi thay biến môi trường, chạy lại ca kiểm IP trước khi crawl.
Gỡ cấu hình thử và giữ bí mật
Sau khi thử xong, xóa các tệp có mật khẩu thử, xóa lịch sử lệnh có chuỗi proxy và thu hồi tài khoản proxy thử nếu đã dùng tài khoản thật. Trên máy chủ CI, đặt PROXY_USER và PROXY_PASS vào mục secret, không ghi vào tệp cấu hình pipeline.
Một mẹo nhỏ: thêm một dòng kiểm trong mã khởi động, nếu PROXY_URL chứa ký tự @ quá một lần thì báo lỗi rõ ràng thay vì để Got báo ENOTFOUND khó hiểu. Kiểm sớm tiết kiệm nhiều giờ dò lỗi về sau.
Checklist Got proxy trước khi chạy thật

Checklist Got proxy trước khi chạy
Bảy điểm cần đánh dấu
Danh sách dưới đây là những gì mình kiểm sau mỗi lần đổi cấu hình. Nó ngắn nhưng bao trùm hầu hết lỗi đã gặp trong lab.
- Agent có đủ khóa http và https, kể cả khi dự án chỉ gọi https, vì redirect có thể đổi giao thức.
- Tài khoản đã mã hóa phần trăm bằng encodeURIComponent, không ghép chuỗi tay.
- SOCKS dùng socks5h:// để proxy phân giải tên miền.
- Có timeout request, vì Got không đặt timeout mặc định.
- Retry không bao gồm POST nếu thao tác không an toàn khi gửi lại.
- maxSockets không vượt hạn mức luồng của gói proxy.
- Ca kiểm IP chạy đầu tiên, so IP ra với IP proxy mong đợi.
Nếu cả bảy điểm đều đạt, phần còn lại thường là chuyện website: tần suất, tiêu đề và cách website phát hiện bot. Đó là bài toán khác, không còn nằm ở cấu hình Got.
Những gì bài này chưa thử
Mình chưa thử với proxy HTTPS, tức kết nối tới chính proxy bằng TLS. Chưa thử HTTP/2 vì trang mẹo của Got đã nói client HTTP/2 tích hợp không hỗ trợ proxy. Chưa thử với gói agent của Apify, chưa thử NTLM và chưa thử trên Linux hay macOS.
Kết quả có thể khác ở Got 11 và các bản CommonJS cũ. Nếu dự án còn ở Got 11, cú pháp agent tương tự nhưng cách nhập gói khác. Hãy chạy lại bảng bảy ca ở trên với đúng phiên bản của mình.
Got proxy và những điều cần nhớ
Got proxy chỉ hoạt động khi truyền agent cho cả http và https, Got không đọc HTTP_PROXY. Mã hóa phần trăm mật khẩu, dùng socks5h:// cho SOCKS, luôn đặt timeout và để POST ngoài danh sách thử lại. Lỗi 407 nằm trong thông điệp chứ không ở statusCode. Cần proxy ổn định cho Got proxy, liên hệ Proxy.vn - Nhà cung cấp dịch vụ proxy chất lượng hàng đầu Việt Nam.