TL;DR
Bạn đã truyền một URL không hợp lệ hoặc URL tương đối vào new URL(), fetch(), hoặc API khác yêu cầu URL tuyệt đối hợp lệ. Cách sửa nhanh: đảm bảo URL có scheme (https:// hoặc http://). Với đường dẫn tương đối, truyền base URL làm tham số thứ hai.
// Sai
const url = new URL('/api/users'); // TypeError [ERR_INVALID_URL]: Invalid URL
// Đúng
const url = new URL('/api/users', 'https://example.com');
console.log(url.href); // https://example.com/api/users
Nguyên nhân
Node.js tuân theo chuẩn WHATWG URL — cùng đặc tả mà trình duyệt sử dụng. Điều đó có nghĩa là new URL(input, base?) hoạt động nghiêm ngặt theo thiết kế: truyền đường dẫn tương đối mà không có base, nó sẽ ném lỗi ngay lập tức, không cần hỏi thêm.
Đây là những tình huống chắc chắn gây ra lỗi:
- Đường dẫn tương đối không có base:
new URL('/path') - URL là
undefined,null, hoặc chuỗi rỗng - URL chứa dấu cách hoặc ký tự đặc biệt chưa được mã hóa như
#hoặc| - Thiếu protocol:
new URL('example.com/path')— trông có vẻ hợp lệ, nhưng không phải - Nội suy biến bị lỗi — chuỗi cuối cùng có giá trị không mong đợi
- Gọi
fetch('/api/data')trong Node.js — khác với trình duyệt, Node không có ngữ cảnh base URL ngầm định
Các cách sửa
1. URL tương đối — truyền base làm tham số thứ hai
Đây là lỗi phổ biến nhất. Trình duyệt có window.location làm base ngầm định; Node.js thì không. Bạn phải cung cấp nó một cách tường minh.
// Sai
const u = new URL('/users/123');
// Đúng
const u = new URL('/users/123', 'https://api.example.com');
console.log(u.href); // https://api.example.com/users/123
2. URL là undefined hoặc null
Bẫy biến môi trường kinh điển — process.env.API_URL sẽ là undefined khi biến chưa được đặt, và new URL(undefined) sẽ bị lỗi ngay lập tức.
const endpoint = process.env.API_URL; // undefined nếu chưa được đặt
new URL(endpoint); // TypeError [ERR_INVALID_URL]: Invalid URL
// Cách sửa: kiểm tra trước khi dùng
if (!endpoint) throw new Error('API_URL env var is not set');
const url = new URL(endpoint);
3. Thiếu protocol / hostname trần
api.example.com/users trông như một URL hợp lệ. Nhưng không phải — ít nhất là với parser WHATWG, vốn yêu cầu scheme rõ ràng.
// Sai — không có scheme
new URL('api.example.com/users');
// Đúng
new URL('https://api.example.com/users');
4. Dấu cách hoặc ký tự không hợp lệ trong URL
Mọi URL được tạo từ input người dùng hoặc dữ liệu động đều cần được mã hóa trước. URLSearchParams xử lý điều này tự động — hãy dùng nó thay vì template literals.
const searchTerm = 'hello world';
// Sai
const u = new URL(`https://example.com/search?q=${searchTerm}`);
// Đúng — URLSearchParams tự mã hóa cho bạn
const u = new URL('https://example.com/search');
u.searchParams.set('q', searchTerm);
console.log(u.href); // https://example.com/search?q=hello+world
5. fetch() với URL tương đối trong Node.js
Node 18+ có sẵn fetch() native, nhưng có một điều cần lưu ý: khác với trình duyệt, nó không có base URL. Các đường dẫn tương đối hoạt động tốt trong React hay trình duyệt sẽ thất bại ở đây. Luôn truyền URL tuyệt đối.
// Sai trong Node.js (hoạt động trên trình duyệt, lỗi ở đây)
const res = await fetch('/api/data');
// Đúng
const BASE = process.env.API_URL ?? 'http://localhost:3000';
const res = await fetch(`${BASE}/api/data`);
6. Bọc bằng try/catch cho input từ người dùng
Đừng tin vào input bên ngoài. Hãy bọc nó, bắt lỗi, và xử lý thất bại nhẹ nhàng thay vì làm crash tiến trình.
function parseUrl(input) {
try {
return new URL(input);
} catch {
return null; // hoặc ném ra lỗi thân thiện hơn
}
}
const result = parseUrl(userInput);
if (!result) {
console.error('Invalid URL provided:', userInput);
}
7. Xây dựng URL động — dùng URL API đúng cách
Nối chuỗi rất dễ gây lỗi — chỉ cần một dấu gạch chéo thừa hoặc ký tự chưa mã hóa là bạn lại gặp lỗi này. Hãy để URL API xử lý việc tạo path và query thay bạn.
const base = new URL('https://api.example.com');
const endpoint = new URL('/v2/users', base);
endpoint.searchParams.set('page', '2');
endpoint.searchParams.set('limit', '50');
console.log(endpoint.href);
// https://api.example.com/v2/users?page=2&limit=50
Kiểm tra
Dán đoạn code này vào file check-url.js và chạy bằng node check-url.js. Mỗi dòng nên in ra OK:. Dòng nào hiển thị FAIL: cho bạn biết chính xác trường hợp nào vẫn còn lỗi.
const cases = [
['https://example.com/path', undefined],
['/relative', 'https://example.com'],
['https://example.com/search', undefined],
];
for (const [input, base] of cases) {
try {
const u = base ? new URL(input, base) : new URL(input);
console.log('OK:', u.href);
} catch (e) {
console.error('FAIL:', input, '->', e.message);
}
}
Checklist nhanh
- URL có bắt đầu bằng
http://hoặchttps://không? - Biến có thực sự là chuỗi — không phải
undefinedhaynull? - Với đường dẫn tương đối: có truyền base URL làm tham số thứ hai không?
- Có dấu cách hoặc ký tự đặc biệt chưa mã hóa trong URL không?
- Nếu dùng
fetch()trong Node.js: URL có phải là tuyệt đối không?
Đọc thêm
- Tài liệu Node.js: WHATWG URL API — new URL(input, base)
- MDN: URL() constructor
- Chuẩn WHATWG URL: url.spec.whatwg.org

