Node.js fetch proxy: Dùng undici ProxyAgent cho fetch gốc
Node.js fetch proxy là câu hỏi mà rất nhiều lập trình viên gặp khi chuyển từ axios hay node-fetch sang hàm fetch có sẵn của Node 18 trở lên. Hàm này không tự đọc biến HTTP_PROXY như curl, đặt biến xong vẫn đi thẳng ra Internet. Bài này ProxyVN hướng dẫn gắn proxy cho fetch gốc bằng undici ProxyAgent, đọc proxy từ biến môi trường, dùng SOCKS5, xoay proxy theo yêu cầu và sửa các lỗi hay gặp. Tham khảo dịch vụ tại ProxyVN.
Tổng quan về Node.js fetch proxy
Trước khi viết mã, anh em cần hiểu vì sao fetch của Node cư xử khác trình duyệt và khác các thư viện cũ. Hiểu phần này sẽ đỡ mất cả buổi thử đi thử lại biến môi trường.
fetch trong Node thực chất là undici
Từ Node 18, hàm `fetch` có sẵn ở phạm vi toàn cục mà không cần cài gói nào. Theo tài liệu globals của Node.js, phần cài đặt bên dưới là undici, thư viện HTTP client viết lại từ đầu do chính đội Node phát triển. Undici không dùng module `http` cũ, nên các agent quen thuộc như `https-proxy-agent` không gắn được vào fetch.
Mỗi bản Node đóng gói sẵn một phiên bản undici cố định. Theo kho mã undici trên GitHub, Node 18 dùng undici 5.x, Node 20 và 22 dùng 6.x, Node 24 dùng 7.x. Anh em kiểm tra bằng lệnh `node -p process.versions.undici`.
Vì sao đặt HTTP_PROXY mà không có tác dụng
Trình duyệt dùng proxy của hệ điều hành, curl đọc biến `HTTP_PROXY`, `HTTPS_PROXY`. Còn fetch của Node thì mặc định bỏ qua tất cả các biến này. Đặt biến môi trường xong rồi chạy script, yêu cầu vẫn đi thẳng bằng IP của máy. Đây là nguyên nhân số một khiến anh em tưởng proxy hỏng.
Lý do là đội Node muốn tránh thay đổi hành vi bất ngờ cho các ứng dụng đang chạy. Việc đọc biến môi trường chỉ được bật khi lập trình viên chủ động yêu cầu, bằng mã hoặc bằng cờ dòng lệnh ở các bản mới.
Khác biệt với fetch trên trình duyệt
Trên trình duyệt, fetch không có khái niệm proxy riêng. Mọi yêu cầu đi theo cấu hình proxy của trình duyệt hoặc hệ điều hành, mã JavaScript không thể đổi proxy cho từng yêu cầu. Đó là quyết định bảo mật, tránh trang web tự ý định tuyến lưu lượng của người dùng.
Fetch trong Node thì khác, nó chạy trên máy chủ hoặc máy cá nhân với quyền của lập trình viên. Vì vậy undici mở ra tuỳ chọn dispatcher để mã tự quyết định đường đi. Đây cũng là lý do mã fetch chép từ trình duyệt sang Node chạy được, nhưng mọi hướng dẫn proxy cho trình duyệt đều không áp dụng.
Ba cách gắn proxy cho fetch
Hiện có ba hướng chính, mỗi hướng hợp một hoàn cảnh:
- ProxyAgent của undici: tạo agent trỏ tới proxy rồi truyền vào từng yêu cầu hoặc đặt làm mặc định toàn cục. Linh hoạt nhất, chạy trên mọi bản Node từ 18.
- EnvHttpProxyAgent: agent tự đọc `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`, hợp khi cấu hình theo môi trường.
- Cờ NODE_USE_ENV_PROXY: Node bản mới tự đọc biến môi trường mà không cần sửa mã.
Phần dưới đi qua lần lượt cả ba, kèm mã chạy được.
Cách kiểm tra Node.js fetch proxy đã hoạt động chưa

fetch gốc bỏ qua biến môi trường
Bước đầu tiên luôn là có một cách kiểm tra đáng tin cậy. Không có bước này, anh em không biết yêu cầu có thực sự đi qua proxy hay không.
Script kiểm tra IP
Gọi một dịch vụ trả về IP công khai là cách nhanh nhất. Chạy script dưới đây trước khi gắn proxy để ghi nhớ IP thật của máy:
// kiem-tra-ip.mjs
const res = await fetch('https://api.ipify.org?format=json');
console.log(await res.json());
node kiem-tra-ip.mjs
HTTPS_PROXY=http://ip-proxy:port node kiem-tra-ip.mjs
Hai lần chạy trả về cùng một IP chứng minh fetch đang bỏ qua biến môi trường. Sau khi gắn proxy đúng cách, IP in ra phải là IP của proxy.
Kiểm tra proxy bằng curl trước
Trước khi nghi ngờ mã Node, anh em xác nhận proxy còn sống bằng curl. Nếu curl lỗi thì vấn đề nằm ở proxy hoặc mạng, sửa mã Node cũng vô ích:
curl -x http://user:pass@ip-proxy:port https://api.ipify.org
Định dạng chuỗi proxy cũng hay gây lỗi khi nhà cung cấp giao dạng `ip:port:user:pass`. Bài định dạng proxy hướng dẫn chuyển sang dạng URL mà undici hiểu được.
Dùng undici ProxyAgent cho Node.js fetch proxy
Đây là cách chuẩn nhất và chạy được trên mọi bản Node có fetch. Anh em cài gói undici từ npm để có lớp ProxyAgent, rồi truyền nó vào fetch.
Cài đặt gói undici
Fetch gốc không cho truy cập trực tiếp lớp ProxyAgent, nên phải cài gói riêng:
npm install undici
Theo tài liệu undici, gói npm và bản đóng gói trong Node chia sẻ chung dispatcher toàn cục, nên ProxyAgent từ gói npm vẫn dùng được với fetch gốc. Tuy vậy, để tránh lệch phiên bản giữa hai bản undici, ProxyVN khuyên nhập luôn hàm `fetch` từ gói undici trong các dự án mới.
Gắn proxy cho từng yêu cầu
Cách rõ ràng nhất là truyền tuỳ chọn `dispatcher` vào từng lời gọi fetch. Theo tài liệu ProxyAgent của undici, agent nhận địa chỉ proxy dạng URL:
import { fetch, ProxyAgent } from 'undici';
const proxyAgent = new ProxyAgent('http://ip-proxy:port');
const res = await fetch('https://api.ipify.org?format=json', {
dispatcher: proxyAgent,
});
console.log(res.status, await res.json());
Cách này cho phép mỗi yêu cầu dùng một proxy khác nhau, hoặc chỉ một số yêu cầu đi qua proxy. Các lời gọi không truyền dispatcher vẫn đi thẳng như cũ.
Đặt proxy mặc định cho toàn bộ ứng dụng
Khi muốn mọi lời gọi fetch trong ứng dụng đều đi qua proxy, kể cả lời gọi bên trong thư viện của bên thứ ba, anh em dùng `setGlobalDispatcher`:
import { ProxyAgent, setGlobalDispatcher } from 'undici';
setGlobalDispatcher(new ProxyAgent('http://ip-proxy:port'));
// Từ đây mọi fetch toàn cục đều đi qua proxy
const res = await fetch('https://api.ipify.org?format=json');
console.log(await res.json());
Đặt dòng này ở tệp khởi động đầu tiên của ứng dụng. Lưu ý dispatcher toàn cục ảnh hưởng tới cả lời gọi tới localhost, nên nếu ứng dụng gọi dịch vụ nội bộ, anh em cần EnvHttpProxyAgent với NO_PROXY ở phần sau.
Proxy có tên đăng nhập và mật khẩu
Proxy thương mại thường yêu cầu xác thực. Undici hỗ trợ truyền thông tin đăng nhập qua tuỳ chọn `token` dưới dạng header Proxy-Authorization:
import { fetch, ProxyAgent } from 'undici';
const user = 'tendangnhap';
const pass = 'matkhau';
const proxyAgent = new ProxyAgent({
uri: 'http://ip-proxy:port',
token: `Basic ${Buffer.from(`${user}:${pass}`).toString('base64')}`,
});
const res = await fetch('https://api.ipify.org?format=json', {
dispatcher: proxyAgent,
});
console.log(await res.json());
Các bản undici gần đây cũng đọc được thông tin đăng nhập ghi thẳng trong URL như `http://user:pass@ip:port`. Nhưng dùng `token` là cách chạy ổn định trên mọi phiên bản. Nếu mật khẩu có ký tự đặc biệt như `@` hay `:`, cách token còn tránh được lỗi phân tích URL.
Đọc proxy từ biến môi trường cho Node.js fetch proxy

Gắn dispatcher cho từng yêu cầu
Khi cùng một mã chạy ở nhiều môi trường, máy lập trình không cần proxy còn máy chủ công ty bắt buộc qua proxy, đọc cấu hình từ biến môi trường là cách gọn nhất.
EnvHttpProxyAgent
Undici cung cấp lớp EnvHttpProxyAgent tự đọc các biến `HTTP_PROXY`, `HTTPS_PROXY` và `NO_PROXY`, cả viết hoa lẫn viết thường. Nó chọn proxy theo giao thức của địa chỉ đích và bỏ qua proxy với các địa chỉ nằm trong NO_PROXY:
import { EnvHttpProxyAgent, setGlobalDispatcher } from 'undici';
setGlobalDispatcher(new EnvHttpProxyAgent());
const res = await fetch('https://api.ipify.org?format=json');
console.log(await res.json());
HTTPS_PROXY=http://user:pass@ip-proxy:port \
NO_PROXY=localhost,127.0.0.1,.noibo.local \
node app.mjs
Cách viết NO_PROXY đúng chuẩn, ví dụ dấu chấm đầu tên miền hay dải IP, đã có trong bài no_proxy là gì. Đây là lựa chọn ProxyVN khuyên dùng cho ứng dụng chạy trong Docker hay máy chủ CI.
Cờ NODE_USE_ENV_PROXY ở Node bản mới
Các bản Node gần đây có hỗ trợ proxy dựng sẵn. Theo tài liệu dòng lệnh của Node.js, biến `NODE_USE_ENV_PROXY=1` được thêm từ Node 24.0.0 và 22.21.0, cờ `--use-env-proxy` thêm từ 24.5.0 và 22.21.0. Khi bật, Node đọc `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY` lúc khởi động và định tuyến yêu cầu qua proxy đó:
NODE_USE_ENV_PROXY=1 HTTPS_PROXY=http://ip-proxy:port node app.mjs
node --use-env-proxy app.mjs
Tính năng đang ở mức ổn định 1.1, nghĩa là còn trong giai đoạn phát triển tích cực. Tài liệu cũng ghi rõ tính năng này dành cho proxy được phép trong môi trường triển khai, ví dụ khi tường lửa công ty bắt buộc đi qua proxy. Với dự án cần chạy trên nhiều phiên bản Node, EnvHttpProxyAgent vẫn an toàn hơn.
Thứ tự ưu tiên khi kết hợp
Nếu vừa bật cờ vừa đặt `setGlobalDispatcher` trong mã, dispatcher đặt trong mã sẽ được dùng. Dispatcher truyền trực tiếp vào lời gọi fetch lại được ưu tiên hơn dispatcher toàn cục. Nắm thứ tự này giúp anh em hiểu vì sao một yêu cầu cụ thể không đi qua proxy dù đã cấu hình toàn cục.
Dùng SOCKS5 với Node.js fetch proxy
ProxyAgent của undici xử lý proxy HTTP, kết nối HTTPS được đi qua bằng phương thức CONNECT. Với proxy SOCKS5, anh em cần thêm một lớp khác.
Dùng gói fetch-socks
Gói `fetch-socks` tạo dispatcher SOCKS tương thích với fetch của undici. Đây là ví dụ triển khai phổ biến trong cộng đồng:
npm install undici fetch-socks
import { fetch } from 'undici';
import { socksDispatcher } from 'fetch-socks';
const dispatcher = socksDispatcher({
type: 5,
host: 'ip-proxy',
port: 1080,
userId: 'tendangnhap',
password: 'matkhau',
});
const res = await fetch('https://api.ipify.org?format=json', { dispatcher });
console.log(await res.json());
Các bản undici mới cũng bắt đầu có lớp agent SOCKS5 riêng. Khi dự án đã nâng lên bản đó, anh em có thể bỏ gói phụ, nhưng cần kiểm tra tài liệu đúng phiên bản đang dùng.
Với node-fetch và module http
Dự án cũ dùng node-fetch hay module `https` thì dùng `socks-proxy-agent` hoặc `https-proxy-agent` truyền qua tuỳ chọn `agent`. Hai gói này không dùng được với fetch gốc vì khác cơ chế bên dưới. Đây là chỗ nhiều anh em chép mã từ bài viết cũ rồi thắc mắc vì sao không chạy.
Thư viện axios cũng có cách cấu hình proxy riêng, khác hẳn fetch. Bài axios proxy hướng dẫn chi tiết cho thư viện này, kể cả phần SOCKS5.
Xoay proxy theo yêu cầu với Node.js fetch proxy

Xoay vòng nhiều proxy
Công việc thu thập dữ liệu thường cần chia yêu cầu qua nhiều IP. Với fetch, cách làm gọn là tạo sẵn một danh sách agent rồi chọn agent cho từng yêu cầu.
Tạo danh sách agent dùng lại
Tạo agent mới cho mỗi yêu cầu sẽ mất kết nối giữ sẵn và làm chậm đáng kể. Cách đúng là tạo một lần, dùng lại nhiều lần:
import { fetch, ProxyAgent } from 'undici';
const danhSachProxy = [
'http://user:pass@ip1:port',
'http://user:pass@ip2:port',
'http://user:pass@ip3:port',
];
const agents = danhSachProxy.map((uri) => new ProxyAgent(uri));
let viTri = 0;
function layAgent() {
const agent = agents[viTri % agents.length];
viTri++;
return agent;
}
for (const url of ['https://api.ipify.org', 'https://api.ipify.org', 'https://api.ipify.org']) {
const res = await fetch(url, { dispatcher: layAgent() });
console.log(await res.text());
}
Mỗi lần chạy vòng lặp, yêu cầu đi qua một proxy khác theo thứ tự xoay vòng. Ví dụ này dùng cách xoay đơn giản, anh em có thể thay bằng chọn ngẫu nhiên hoặc chọn theo tên miền đích.
Giữ phiên trên cùng một IP
Một số trang gắn phiên đăng nhập với IP. Đổi IP giữa chừng sẽ bị đăng xuất hoặc bị yêu cầu xác minh. Với các trường hợp đó, anh em gán một agent cố định cho từng tài khoản, ví dụ dùng một bảng ánh xạ từ tên tài khoản tới agent, thay vì xoay ngẫu nhiên.
Kiểm tra proxy trước khi đưa vào vòng xoay
Một proxy chết trong danh sách sẽ làm một phần yêu cầu thất bại đều đặn. Trước mỗi đợt chạy, anh em gọi thử một địa chỉ nhẹ qua từng agent, đặt thời gian chờ ngắn khoảng năm giây, proxy nào lỗi thì loại khỏi danh sách. Bước kiểm tra này mất vài giây nhưng tiết kiệm rất nhiều thời gian đọc nhật ký lỗi sau đó.
Trong lúc chạy, nếu một proxy lỗi liên tiếp ba lần, nên tạm đưa nó ra khỏi vòng xoay vài phút rồi thử lại. Cách làm này giống kiểm tra sức khoẻ bị động của các bộ cân bằng tải, áp dụng ở phía client.
Giới hạn đồng thời và tốc độ
Gửi hàng trăm yêu cầu cùng lúc qua một proxy dễ làm proxy quá tải và trang đích chặn. Anh em nên giới hạn số yêu cầu đồng thời, ví dụ bằng gói `p-limit`, và thêm khoảng nghỉ ngẫu nhiên giữa các yêu cầu. Tôn trọng tốc độ hợp lý vừa giữ proxy bền, vừa tránh gây tải cho trang đích.
So sánh Node.js fetch proxy với axios và trình duyệt tự động
Fetch không phải lựa chọn duy nhất để gọi HTTP qua proxy trong Node. Tuỳ bài toán, công cụ khác có thể hợp hơn.
Bảng so sánh nhanh
Bảng dưới so sánh bốn cách phổ biến:
Công cụ |
Cách gắn proxy |
SOCKS5 |
Hợp với |
|---|---|---|---|
fetch gốc với undici |
dispatcher, ProxyAgent |
Cần gói phụ |
Dự án mới, ít phụ thuộc |
axios |
Tuỳ chọn proxy hoặc agent |
Qua agent |
Dự án cũ, cần interceptor |
Puppeteer |
Tham số khởi động trình duyệt |
Có |
Trang cần chạy JavaScript |
Playwright |
Tuỳ chọn proxy khi launch hoặc context |
Có |
Trang động, nhiều trình duyệt |
Khi trang đích render bằng JavaScript và chặn yêu cầu không có trình duyệt thật, fetch không đủ. Lúc đó anh em chuyển sang proxy cho Puppeteer hoặc proxy cho Playwright.
Khi nào fetch là đủ
Fetch hợp với gọi API trả JSON, tải trang tĩnh, kiểm tra trạng thái trang, gửi webhook. Nó nhẹ, không phải chạy trình duyệt nặng hàng trăm MB, xử lý hàng nghìn yêu cầu mỗi phút trên máy chủ nhỏ. Với API công khai, fetch qua proxy thường nhanh và rẻ hơn trình duyệt tự động nhiều lần.
Sửa lỗi thường gặp với Node.js fetch proxy

Đọc lỗi kết nối qua proxy
Lỗi của fetch thường chỉ hiện dòng "fetch failed" chung chung. Thông tin thật nằm trong thuộc tính `cause` của lỗi, đọc nó là bước đầu tiên.
Đọc nguyên nhân thật của lỗi
Bọc lời gọi trong try catch và in ra `error.cause` để thấy mã lỗi cụ thể:
try {
await fetch('https://example.com', { dispatcher: proxyAgent });
} catch (err) {
console.error(err.message);
console.error(err.cause?.code, err.cause?.message);
}
Mã lỗi trong `cause` cho biết vấn đề nằm ở tầng nào: kết nối tới proxy, xác thực, hay chứng chỉ của trang đích.
UND_ERR_CONNECT_TIMEOUT và ECONNREFUSED
Lỗi hết thời gian kết nối nghĩa là không mở được kết nối tới proxy trong thời gian quy định, mặc định khoảng 10 giây. Proxy chết, sai IP, sai cổng, hoặc tường lửa chặn đều gây ra lỗi này. ECONNREFUSED nghĩa là máy proxy còn sống nhưng cổng đó không có dịch vụ, thường do nhầm cổng HTTP với cổng SOCKS5.
Với proxy chậm, anh em có thể tăng thời gian chờ qua tuỳ chọn `connect: { timeout: 20000 }` khi tạo agent. Nhưng nếu proxy thường xuyên cần hơn 10 giây để kết nối, nên đổi proxy thay vì tăng thời gian chờ.
Lỗi 407 Proxy Authentication Required
Khi thông tin đăng nhập sai, undici báo lỗi kiểu phản hồi proxy là 407 thay vì 200 trong lúc mở đường hầm. Kiểm tra lại tên đăng nhập, mật khẩu, và cách mã hoá base64. Lỗi hay gặp là quên chữ `Basic ` phía trước chuỗi token, hoặc mật khẩu có ký tự đặc biệt chưa được mã hoá khi ghi trong URL.
Nếu nhà cung cấp dùng xác thực theo IP whitelist, anh em phải thêm IP của máy chạy Node vào danh sách cho phép. Máy chủ đổi IP thì proxy sẽ từ chối ngay.
Lỗi chứng chỉ tự ký
Trong mạng công ty, proxy thường giải mã HTTPS bằng chứng chỉ riêng, Node báo lỗi `SELF_SIGNED_CERT_IN_CHAIN` hoặc `UNABLE_TO_VERIFY_LEAF_SIGNATURE`. Cách đúng là thêm chứng chỉ gốc của công ty qua biến `NODE_EXTRA_CA_CERTS=/duong-dan/ca.pem`. Tắt kiểm tra chứng chỉ bằng `NODE_TLS_REJECT_UNAUTHORIZED=0` chỉ nên dùng khi thử nghiệm, không dùng cho môi trường thật.
npm install bị chặn trong cùng mạng
Nhiều khi lỗi không nằm ở fetch mà ở bước cài gói. Máy sau proxy công ty thường cài npm thất bại trước cả khi chạy mã. Cấu hình proxy cho npm là việc riêng, bài npm proxy hướng dẫn chi tiết cho npm, yarn và pnpm.
Cấu hình Node.js fetch proxy trên Windows, Docker và CI
Cùng một đoạn mã nhưng mỗi môi trường đặt biến và chạy lệnh theo cách khác nhau. Phần lớn lỗi "chạy trên máy tôi được" đến từ chỗ này chứ không phải từ mã.
Đặt biến môi trường trên Windows
Cú pháp `HTTPS_PROXY=... node app.mjs` chỉ chạy trên shell kiểu Unix như bash hay zsh. Trên PowerShell, anh em đặt biến cho phiên hiện tại rồi mới chạy lệnh:
$env:HTTPS_PROXY = "http://user:pass@ip-proxy:port"
$env:NO_PROXY = "localhost,127.0.0.1"
node app.mjs
Trên Command Prompt cũ, dùng `set HTTPS_PROXY=http://user:pass@ip-proxy:port` rồi chạy lệnh. Với dự án cần chạy trên nhiều hệ điều hành, gói `cross-env` cho phép viết một dòng lệnh trong `package.json` chạy được ở mọi nơi, đỡ phải giải thích cho từng thành viên trong nhóm.
Trong Docker
Biến môi trường truyền vào container bằng tham số `-e` hoặc mục `environment` trong tệp compose. Lưu ý quan trọng là biến dùng lúc build image và lúc chạy container khác nhau. Biến đặt trong `environment` chỉ có tác dụng khi chạy, còn bước `npm install` trong Dockerfile cần proxy thì phải truyền qua `build args`.
Một lỗi hay gặp là đặt proxy bằng `localhost` hoặc `127.0.0.1` khi proxy chạy trên máy chủ. Bên trong container, localhost là chính container đó. Anh em dùng `host.docker.internal` trên Docker Desktop, hoặc IP cổng mạng Docker trên Linux.
Trong hệ thống CI
Các hệ thống như GitHub Actions hay GitLab CI cho phép khai báo biến bí mật ở phần cài đặt dự án. Anh em lưu chuỗi proxy có mật khẩu dưới dạng biến bí mật, rồi ánh xạ vào biến `HTTPS_PROXY` trong bước chạy kiểm thử. Như vậy mật khẩu không xuất hiện trong mã nguồn hay nhật ký build.
Nếu chỉ một vài kiểm thử cần proxy, ví dụ kiểm thử gọi API theo vùng, nên truyền dispatcher riêng cho các kiểm thử đó. Đặt proxy toàn cục cho cả bộ kiểm thử sẽ làm chậm và có thể phá các kiểm thử gọi dịch vụ giả lập trên localhost.
Node.js fetch proxy với TypeScript và CommonJS
Các ví dụ ở trên dùng cú pháp ES module với `import`. Dự án cũ dùng CommonJS hoặc dự án TypeScript có vài khác biệt nhỏ cần biết để không mất thời gian sửa lỗi biên dịch.
Dùng với CommonJS
Gói undici hỗ trợ cả hai kiểu module. Với dự án dùng `require`, cú pháp như sau:
const { fetch, ProxyAgent } = require('undici');
const proxyAgent = new ProxyAgent('http://ip-proxy:port');
(async () => {
const res = await fetch('https://api.ipify.org', { dispatcher: proxyAgent });
console.log(await res.text());
})();
CommonJS không cho dùng `await` ở cấp cao nhất, nên phải bọc trong một hàm async. Đây là lỗi cú pháp hay gặp khi chép mã từ ví dụ ES module sang.
Dùng với TypeScript
Undici có sẵn định nghĩa kiểu, không cần cài thêm gói `@types`. Khi truyền `dispatcher` vào fetch toàn cục của Node, TypeScript có thể báo lỗi vì kiểu RequestInit của DOM không có thuộc tính này. Cách gọn nhất là nhập luôn hàm `fetch` từ undici, khi đó kiểu dữ liệu khớp với ProxyAgent.
Nếu dự án bắt buộc dùng fetch toàn cục, anh em đặt `setGlobalDispatcher` thay vì truyền dispatcher cho từng lời gọi. Cách này tránh được lỗi kiểu mà vẫn đi qua proxy như mong muốn.
Bảo mật thông tin Node.js fetch proxy
Chuỗi proxy chứa tên đăng nhập và mật khẩu, lộ ra là người khác dùng được băng thông của anh em. Vài thói quen nhỏ giúp tránh rủi ro này.
Không ghi thẳng vào mã nguồn
Mật khẩu proxy nên nằm trong tệp `.env` được liệt kê trong `.gitignore`, hoặc trong kho bí mật của hệ thống triển khai. Node 20.6 trở lên có cờ `--env-file=.env` để nạp tệp này mà không cần gói dotenv. Đẩy mật khẩu lên kho mã công khai, dù chỉ một lần rồi xoá, vẫn có thể bị công cụ quét tự động thu thập.
Che mật khẩu trong nhật ký
Khi in lỗi hoặc ghi nhật ký, chuỗi URL proxy có thể lọt vào kèm mật khẩu. Anh em viết một hàm nhỏ thay phần mật khẩu bằng dấu sao trước khi ghi. Nhật ký thường được gửi sang dịch vụ bên thứ ba, nên mật khẩu trong nhật ký coi như đã lộ ra ngoài.
Mẫu cấu hình Node.js fetch proxy cho dự án thực tế
Phần này gom các mảnh ở trên thành một mô-đun nhỏ, đọc cấu hình từ biến môi trường, có thời gian chờ và thử lại. Anh em có thể chép vào dự án rồi điều chỉnh.
Mô-đun http-client dùng chung
Ví dụ triển khai dưới đây do ProxyVN viết, dùng EnvHttpProxyAgent khi có biến môi trường và tự thử lại khi gặp lỗi mạng tạm thời:
// http-client.mjs
import { fetch, EnvHttpProxyAgent, Agent } from 'undici';
const coProxy = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
const dispatcher = coProxy
? new EnvHttpProxyAgent({ connect: { timeout: 15000 } })
: new Agent({ connect: { timeout: 15000 } });
export async function goi(url, tuyChon = {}, soLanThu = 3) {
for (let lan = 1; lan <= soLanThu; lan++) {
try {
const res = await fetch(url, { ...tuyChon, dispatcher });
if (res.status === 429 || res.status >= 500) throw new Error(`HTTP ${res.status}`);
return res;
} catch (err) {
if (lan === soLanThu) throw err;
await new Promise((r) => setTimeout(r, 1000 * lan));
}
}
}
Mô-đun này cho phép cùng một mã chạy ở máy lập trình không có proxy và ở máy chủ có proxy mà không sửa dòng nào. Thời gian nghỉ tăng dần giữa các lần thử giúp tránh dồn dập khi trang đích đang quá tải.
Ghi nhật ký IP đã dùng
Khi chạy nhiều proxy, anh em nên ghi lại yêu cầu nào đi qua proxy nào và kết quả ra sao. Nhật ký này giúp phát hiện proxy chết hoặc IP bị trang đích chặn, để loại khỏi danh sách kịp thời. Đừng ghi mật khẩu proxy vào nhật ký, chỉ ghi IP và cổng.
Chọn proxy phù hợp cho công việc
Với gọi API thông thường, proxy datacenter có tốc độ cao và giá tốt. Với trang có hệ thống chống bot khắt khe, proxy dân cư tĩnh cho tỷ lệ thành công cao hơn vì IP thuộc nhà mạng gia đình. Khi cần IP Việt Nam, anh em có thể mua proxy tại ProxyVN, gồm dân cư tĩnh Viettel, VNPT, FPT và datacenter Việt Nam, hỗ trợ HTTP và SOCKS5, cấp sẵn tên đăng nhập và mật khẩu dùng ngay với ProxyAgent.
Kết luận
Node.js fetch proxy không tự hoạt động bằng biến môi trường như curl. Anh em dùng undici ProxyAgent cho từng yêu cầu hoặc toàn cục, EnvHttpProxyAgent khi cấu hình theo môi trường, gói phụ cho SOCKS5, và đọc `error.cause` khi gặp lỗi. Cần proxy ổn định cho dự án, hãy liên hệ Proxy.vn - Nhà cung cấp dịch vụ proxy chất lượng hàng đầu Việt Nam khi triển khai Node.js fetch proxy.