Tôi đã không ít lần thức khuya chỉ để gỡ lỗi những script vốn dĩ chỉ nên “tải một tệp rồi xong”. Phần lớn trường hợp, thủ phạm lại chính là cURL đang làm đúng những gì tôi yêu cầu, chứ không phải những gì tôi thực sự muốn. Hóa ra có một khoảng cách rất lớn giữa câu “curl -O chạy được” và “curl -O chạy ổn định trong môi trường production.”
Chính vì khoảng cách đó mà bài hướng dẫn này ra đời. cURL được cài sẵn trên macOS, hầu hết các bản phân phối Linux, và Windows 10 trở lên, nghĩa là rất có thể máy bạn đã có sẵn công cụ này. Nhưng giữa lỗi chuyển hướng âm thầm, các mã 403 bí ẩn, và bước nhảy từ “tải một tệp” sang “tải 500 tệp mà không làm nghẽn terminal”, vẫn còn vô số chỗ dễ mắc kẹt. Tôi sẽ đi qua các cờ lệnh quan trọng, những lệnh thực tế tôi hay dùng, các lỗi thường gặp nhất, và cả lúc cURL thật sự không còn giúp được nữa — cùng lựa chọn thay thế phù hợp.
cURL là gì (và vì sao bạn nên quan tâm)?
cURL là một công cụ dòng lệnh miễn phí, mã nguồn mở, dùng để truyền dữ liệu tới hoặc từ máy chủ thông qua URL. Nó hỗ trợ HTTP, HTTPS, FTP, SFTP và rất nhiều giao thức khác, nên xuất hiện khắp nơi từ script bash, Dockerfile cho đến pipeline CI. Ẩn phía sau, lệnh curl bạn gõ trong terminal sử dụng libcurl, thư viện truyền dữ liệu bằng C mà rất nhiều ứng dụng và binding ngôn ngữ lập trình tích hợp. Ví dụ, extension cURL của PHP là một trường hợp như vậy; còn thư viện Requests phổ biến của Python là một HTTP client riêng, xây dựng trên urllib3 chứ không phải libcurl.
Phiên bản ổn định hiện tại tại thời điểm viết bài là curl 8.21.0, phát hành vào tháng 6 năm 2026 — nhưng đừng mặc định rằng hệ điều hành của bạn đang đi kèm đúng bản build đó. Các bản curl do distro đóng gói thường chậm hơn dự án gốc vài tháng, thậm chí lâu hơn, nên tốt nhất hãy chạy curl --version trước khi cho rằng một cờ lệnh như --parallel đã khả dụng.
Vì sao nên tải tệp bằng cURL? Các trường hợp sử dụng hàng đầu
Tôi thường được hỏi: tại sao phải dùng công cụ dòng lệnh trong khi trình duyệt tải tệp rất ổn? Câu trả lời thật lòng là: trình duyệt rất tốt cho đến khi bạn cần tự động hóa.
| Trường hợp sử dụng | Vì sao cURL nổi bật |
|---|---|
| Tải binary trong pipeline CI/CD | Có thể viết script, không cần giao diện đồ họa |
| Lấy phản hồi API hoặc xuất dữ liệu | Hỗ trợ header tùy chỉnh, xác thực, và chuyển đầu ra qua pipeline |
| Tiếp tục tải tệp lớn qua SSH | Có sẵn chức năng tiếp tục tải (-C -) |
| Tự động tải theo lịch (cron) | Nhẹ, dễ kết hợp với shell script |
| Lấy tệp phía sau lớp đăng nhập | Cờ xác thực linh hoạt (basic, token, cookie, .netrc) |
Tải bằng trình duyệt là thao tác thủ công, chỉ dùng một lần. cURL biến thao tác đó thành thứ bạn có thể lên lịch, nối vào pipeline, thử lại khi lỗi, và chạy đồng nhất trên hàng trăm máy chủ cùng lúc. Đó chính là sức hút của nó — không hào nhoáng hơn, chỉ là lặp lại được.

Các cờ cURL thiết yếu để tải tệp
Tôi thường quay lại khoảng hơn chục cờ lệnh quen thuộc cho 90% công việc của mình. Đây là phần “phao cứu sinh” mà giá như có ai đưa cho tôi từ nhiều năm trước, được nhóm theo đúng chức năng thực tế.
Cờ xuất ra và lưu tệp
-O(--remote-name) lưu tệp bằng phần cuối của URL làm tên file. Tiện, nhưng có thể âm thầm ghi đè lên tệp đã tồn tại cùng tên.-o <filename>(--output) cho phép bạn tự chọn chính xác tên tệp:curl -o report.pdf https://example.com/downloads/file.pdf.-J(--remote-header-name) dùng tên tệp từ headerContent-Dispositioncủa máy chủ thay vì lấy từ URL. Cách này rất tiện cho việc tải từ API, nhưng hãy coi tên tệp do máy chủ cung cấp là dữ liệu không đáng tin — nên tải vào một thư mục riêng thay vì thư mục home, đúng như khuyến nghị bảo mật của curl.
Các cờ hành vi mà mọi lượt tải đều cần
-L(--location) bảo curl đi theo các chuyển hướng HTTP. Nếu không có nó, phản hồi 3xx có thể bị lưu thành một trang HTML chuyển hướng nhỏ xíu thay vì tệp thật — đây là lỗi “sao file tải về bị hỏng” mà tôi gặp nhiều nhất.-C -(--continue-at -) tiếp tục tải từ đúng chỗ bị gián đoạn.-s/-Schạy ở chế độ im lặng nhưng vẫn hiện lỗi — rất hợp cho script khi bạn không muốn thanh tiến trình làm rối log.--limit-rate 1Mgiới hạn băng thông (hữu ích khi dùng chung mạng hoặc không muốn chiếm hết đường truyền tính cước).--connect-timeout 10và--max-time 300ngăn kết nối treo làm script đứng chết ở đó mãi.--retry 3và--retry-delay 5tự thử lại khi lỗi tạm thời — theo trang man của curl, chỉ nên ghép thêm--retry-all-errorskhi việc lặp lại đúng y nguyên request đó thực sự an toàn.
Cờ tiến trình và gỡ lỗi
-#hiển thị thanh tiến trình đơn giản thay cho bảng thống kê mặc định.-vxuất ra thông tin chi tiết, bao gồm toàn bộ header request/response — đây là lựa chọn tôi dùng khi có gì đó hoạt động bất thường.-I(--head) chỉ lấy header phản hồi, rất phù hợp để kiểm tra trước khi quyết định tải một tệp lớn.-wcho phép in đầu ra tùy chỉnh sau khi truyền xong, ví dụcurl -o /dev/null -s -w "%{http_code}\n" <url>để chỉ kiểm tra mã trạng thái.
Trước khi bắt đầu
- Độ khó: Từ cơ bản đến trung cấp (phần batch và xác thực sẽ nâng cao hơn một chút)
- Thời gian cần thiết: Khoảng 15–20 phút để đi qua các lệnh cốt lõi
- Bạn cần gì: Một terminal (macOS Terminal, shell Linux, hoặc Windows PowerShell/WSL), cURL đã cài sẵn (kiểm tra bằng
curl --version), và một URL thử nghiệm — tôi sẽ dùng một asset phát hành công khai trên GitHub làm ví dụ vì nó ổn định và dễ truy cập
Cách tải tệp bằng cURL: hướng dẫn từng bước
Bước 1: Tải một tệp duy nhất
Cú pháp cơ bản nhất: curl -O <url> sẽ lưu tệp theo tên gốc của nó, còn curl -o myfile.zip <url> cho phép bạn đổi tên ngay lúc tải.
curl -LO https://github.com/curl/curl/releases/download/curl-8_21_0/curl-8.21.0.tar.gz
Hiện tại tôi luôn thêm -L, không có ngoại lệ nào cả — tôi đã quá nhiều lần bị redirect biến “lượt tải” thành một file HTML 400 byte mà không hề báo trước. Bạn sẽ thấy thanh tiến trình chạy lên trong terminal, và cuối cùng file nằm trong thư mục hiện tại.
Khi lệnh thành công, thanh tiến trình sẽ đạt 100% và curl-8.21.0.tar.gz sẽ xuất hiện trong thư mục hiện tại. Hãy xác nhận tệp trước khi dùng:
ls -lh curl-8.21.0.tar.gz
Bước 2: Tải và đổi tên tệp
Dùng -o khi bạn muốn đặt tên tệp cục bộ cụ thể thay vì cái tên mà URL vốn có:
curl -L -o curl-latest.tar.gz -S https://github.com/curl/curl/releases/download/curl-8_21_0/curl-8.21.0.tar.gz
-S ở đây sẽ bật lại phần hiển thị lỗi trong trường hợp bạn đã dùng -s ở nơi khác trong script. Bộ này — -L -o <name> -S — gần như là lệnh tải một tệp mặc định của tôi.
Bước 3: Tiếp tục tải khi bị gián đoạn
Nếu một file lớn bị rớt giữa chừng (wifi chập chờn, VPN có vấn đề, v.v.), đừng tải lại từ đầu. Hãy chạy:
curl -C - -LO https://example.com/large-file.iso
Điều cần lưu ý: cách này chỉ hoạt động nếu máy chủ hỗ trợ byte-range request. Accept-Ranges: bytes là tín hiệu tích cực hữu ích, nhưng việc không có nó chưa đủ để kết luận là máy chủ không hỗ trợ range. Cách kiểm tra đáng tin cậy là xem phản hồi thật của máy chủ với một request range: phản hồi có thể tiếp tục tải thường sẽ trả về 206 Partial Content cùng Content-Range hợp lệ. Hãy chạy lệnh tiếp tục tải rồi kiểm tra trạng thái bằng -v hoặc -D -; nếu máy chủ bỏ qua range hoặc từ chối offset, hãy chủ động tải lại từ đầu thay vì cho rằng file dở dang vẫn an toàn.

Bước 4: Tải với thanh tiến trình hoặc ở chế độ im lặng
Nếu muốn giao diện gọn hơn trong terminal tương tác: curl -# -LO <url>. Nếu viết script hoặc cron job và chỉ muốn xem lỗi, không muốn tiếng ồn: curl -sS -LO <url>. Tôi dùng bản im lặng ở hầu hết mọi nơi, trừ lúc gỡ lỗi thủ công.
Bước 5: Giới hạn tốc độ tải
Trên mạng văn phòng dùng chung (hoặc khi tôi không muốn trở thành người “ngốn” hết băng thông trong một cuộc gọi video), tôi sẽ giới hạn tốc độ bằng:
curl --limit-rate 1M -LO https://example.com/big-dataset.zip
Đơn vị là K, M, và G tương ứng với kilobyte, megabyte và gigabyte mỗi giây.
Bước 6: Lưu header phản hồi cùng với tệp
Đôi khi tôi cần biết chính xác máy chủ trả về những gì — loại nội dung, header cache, và các thông tin tương tự — mà không làm terminal rối mắt:
curl -L -D headers.txt -o file.zip https://example.com/file.zip
Lệnh này ghi header phản hồi vào headers.txt trong khi tệp thật được lưu thành file.zip. Rất hữu ích để gỡ lỗi lệch loại nội dung hoặc kiểm tra xem CDN có đang cache đúng thứ bạn nghĩ là nó đang cache hay không.
Mẹo và lỗi thường gặp
- Mẹo: Luôn mặc định dùng
-L. Thực sự tôi không nghĩ ra điểm bất lợi nào khi thêm nó, và tôi đã mất hàng giờ chỉ vì quên. - Mẹo: Khi viết script, hãy kết hợp
--failvới lệnh tải để phản hồi không phải 2xx khiến script thoát lỗi thật sự, thay vì âm thầm lưu một trang lỗi như thể đó là file bạn cần. - Lỗi thường gặp: Đừng ghép
-C -với--remove-on-error— curl ghi rõ hai tùy chọn này không tương thích, vì resume cần file dở dang vẫn phải còn nguyên. - Lỗi thường gặp:
-Ocó thể ghi đè tệp mà không báo trước. Nếu bạn tải hàng loạt vào một thư mục dùng chung, hãy dùng--output-dirđể giữ mọi thứ gọn trong một chỗ.
Cách tải nhiều tệp và tải hàng loạt bằng cURL
Ví dụ với một tệp là phần dễ nhất. Những quy trình thực tế mà tôi xây dựng — lấy dữ liệu xuất hằng đêm, đồng bộ binary giữa các máy build — đều cần xử lý đồng thời, và đây là chỗ mà phần lớn bài hướng dẫn chỉ... dừng lại. Có ba cách đáng biết, mỗi cách là một nấc phức tạp hơn.
Cách 1: Nhiều URL trong một lệnh cURL
Cách đơn giản nhất là liệt kê các URL:
curl -LO https://example.com/a.zip -LO https://example.com/b.zip -LO https://example.com/c.zip
Cách này hoạt động, nhưng là chạy tuần tự — curl tải xong file này mới sang file tiếp theo. Với 3 file thì ổn, với 300 file thì rất mệt.
Cách 2: Tải song song với --parallel (curl 7.66+)
Từ curl 7.66 trở đi, bạn có thể thêm --parallel (hoặc -Z) để tải nhiều URL cùng lúc:
curl --parallel --parallel-max 5 --remote-name-all \
https://example.com/a.zip https://example.com/b.zip https://example.com/c.zip
Điều nên biết: giới hạn song song mặc định thực ra là 50, tức là nhiều kết nối đồng thời hơn mức mà đa số máy chủ — hoặc ngay cả mạng của bạn — sẽ cảm ơn. Tôi thường đặt --parallel-max rõ ràng và thận trọng — thường là 4 đến 8 — thay vì tin vào mặc định.
Cách 3: Dùng xargs và vòng lặp Bash để xử lý danh sách URL
Với một danh sách URL lớn nằm trong file text, tôi thường chọn xargs:
cat urls.txt | xargs -n1 -P 8 curl -O -L
Hoặc nếu muốn kiểm soát nhiều hơn từng job riêng lẻ, tôi dùng vòng lặp bash với tiến trình nền:
while read -r url; do
curl -O -L "$url" &
done < urls.txt
wait
Lệnh wait ở cuối rất quan trọng — nếu không có nó, script sẽ thoát trước khi các lượt tải nền hoàn tất.
Khi nào nên dùng wget hoặc aria2 thay vì cURL
Nói thẳng luôn: cURL không phải lúc nào cũng là công cụ đúng. Nếu bạn cần mirror toàn bộ cây thư mục của một website, wget -r có sẵn chức năng crawl đệ quy theo cách mà cURL vốn không được sinh ra để làm. Nếu bạn cần tải chia đoạn từ nhiều nguồn để tối đa thông lượng cho một file cực lớn, aria2c thực sự nhanh hơn.
| Công cụ | Phù hợp nhất cho |
|---|---|
| cURL | Độ chính xác, viết script, tải một tệp hoặc số lượng nhỏ, làm việc với API |
| wget | Tải đệ quy/mirror toàn bộ site, lấy hàng loạt tệp tĩnh đơn giản hơn |
| aria2 | Tải đa nguồn/chia đoạn, tối đa thông lượng cho file lớn |
Điểm mạnh của cURL luôn là độ chính xác và khả năng kết hợp — piping, scripting, linh hoạt giao thức — chứ không phải kiểu crawl brute-force.
Cách tải tệp được bảo vệ bằng cURL: các mẫu xác thực
Nhiều bài hướng dẫn cURL chỉ dừng ở -u user:pass rồi kết thúc. Đó là dấu vết của một thời kỳ Internet cũ. Năm 2026, những thứ tôi thật sự tải về đến từ REST API, dashboard dùng session, và hệ thống CI — và mỗi loại lại cần một kiểu credential khác nhau.
Basic Auth
curl -u username:password -O https://legacy-server.example.com/file.zip
Ổn cho các server FTP kiểu cũ hoặc endpoint HTTP đơn giản. Chỉ cần nhớ mật khẩu có thể xuất hiện trong lịch sử shell và danh sách tiến trình nếu bạn không cẩn thận — tôi sẽ không dùng cách này cho bất kỳ thứ gì nhạy cảm.
Bearer / OAuth Token Auth
Đây là kiểu xác thực thường bị nói thiếu trong nhiều tài liệu, nhưng lại là kiểu tôi dùng nhiều nhất hiện nay:
curl -H "Authorization: Bearer $GITHUB_TOKEN" \
-LO https://api.github.com/repos/curl/curl/releases/assets/12345
Đó là một mẫu thật để lấy private release asset trên GitHub — chỉ cần thay token và asset ID của bạn vào. REST API và các tài nguyên được bảo vệ bởi OAuth2 gần như đều nói “ngôn ngữ” này.
Xác thực bằng session cookie
Với các web app mà đăng nhập xong sẽ tạo session, hãy lưu cookie jar lúc đăng nhập rồi dùng lại khi tải:
curl -c cookies.txt -d "user=me&pass=secret" https://example.com/login
curl -b cookies.txt -O https://example.com/protected/file.zip
File .netrc cho môi trường script và CI
Đây là cách tôi thích nhất cho mọi thứ chạy không có người giám sát. Tạo file ~/.netrc (hoặc _netrc trên Windows):
machine example.com
login myusername
password mypassword
Khóa quyền truy cập bằng chmod 600 ~/.netrc, rồi dùng nó như sau:
curl --netrc -LO https://example.com/protected-file.zip
Ưu điểm là credential không bao giờ chạm vào lịch sử shell hay mã nguồn script — điều này thật sự quan trọng trong CI/CD, nơi script thường bị ghi log đầy đủ.
| Phương thức xác thực | Cờ/Tùy chọn | Phù hợp nhất cho |
|---|---|---|
| Basic auth | -u user:pass | FTP cũ, HTTP đơn giản |
| Bearer token | -H "Authorization: Bearer <token>" | REST API, OAuth2 |
| Cookie auth | -b cookies.txt (+ -c để lưu) | Ứng dụng web dựa trên session |
File .netrc | --netrc hoặc --netrc-file | CI/CD, môi trường script |

Khắc phục các lỗi tải cURL thường gặp
Đây là phần mà tôi thật sự ước giá như có khi mới bắt đầu, vì gần như chẳng ai nói kỹ. “Tại sao tải bằng curl của tôi không chạy?” là một truy vấn rất thật, rất phổ biến, và cực kỳ gây khó chịu — trong khi cách sửa thường chỉ là một dòng lệnh nếu bạn biết nguyên nhân.
| Triệu chứng | Nguyên nhân có thể | Cách sửa |
|---|---|---|
curl: (60) SSL certificate problem | Chứng chỉ tự ký hoặc đã hết hạn | --cacert <file> hoặc -k (chỉ dùng khi dev) |
403 Forbidden / file rỗng | Máy chủ chặn user agent mặc định của curl | -A "Mozilla/5.0..." hoặc -H "User-Agent: ..." |
Tải lại từ 0 với -C - | Máy chủ không hỗ trợ Range | Kiểm tra bằng curl -I <url> xem có Accept-Ranges: bytes không |
| Lưu file 0 byte | Không theo redirect | Thêm cờ -L |
curl: (28) Operation timed out | Máy chủ chậm hoặc sự cố mạng | --connect-timeout 10 --max-time 300 + --retry 3 |
| Lưu trang HTML thay vì file | Trang cần JavaScript để render | curl không chạy JS — xem phần bên dưới |
Lỗi chứng chỉ SSL: nghĩa là gì và sửa thế nào
Lỗi 60 có nghĩa là curl không thể xác minh chứng chỉ SSL của máy chủ — thường vì chứng chỉ tự ký, hết hạn, hoặc được cấp bởi CA mà curl không tin cậy. Nếu bạn kiểm soát máy chủ, hãy trỏ curl tới đúng CA bundle bằng --cacert /path/to/ca.pem. Cờ -k (--insecure) bỏ qua xác minh hoàn toàn, tạm chấp nhận trong môi trường dev cục bộ, nhưng là ý tưởng cực tệ cho bất kỳ thứ gì chạm vào production hoặc dữ liệu người dùng thật.
Lỗi 403 Forbidden và file tải rỗng
Không ít máy chủ chặn các request tự nhận là curl/8.21.0 (chuỗi User-Agent mặc định của curl), vì nghĩ đó là bot hoặc scraper. Cách sửa thường chỉ là giả làm trình duyệt:
curl -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" -LO https://example.com/file.zip
Để kiểm tra thực sự nhận được gì trước khi tải đầy đủ, tôi thường chạy: curl -o /dev/null -s -w "%{http_code}\n" <url>.
Timeout, retry và kết nối chập chờn
Đây là lệnh tôi sẵn sàng xăm lên tay nếu tôi can đảm hơn với việc xăm mình.
Lệnh tải tôi hay dùng nhất trong production script, ghép mọi cờ độ tin cậy lại với nhau:
curl -L -C - --retry 5 --retry-delay 3 --connect-timeout 10 --max-time 600 --fail -O <url>
Tức là theo redirect, tiếp tục tải, thử lại 5 lần với độ trễ 3 giây, timeout kết nối 10 giây, giới hạn tổng thời gian 10 phút, và thất bại rõ ràng nếu HTTP status xấu — gần như mọi thứ tôi đã học được sau nhiều lần trả giá.
cURL trong tự động hóa thực tế: CI/CD pipeline, piping và an toàn script
Piping đầu ra của cURL sang công cụ khác
curl không nhất thiết phải lưu ra đĩa — pipe thẳng sang lệnh khác là một trong những tính năng bị đánh giá thấp nhất của nó:
curl -sL https://example.com/archive.tar.gz | tar xz
curl -s https://api.example.com/data | jq '.results'
Tải rồi giải nén, hoặc tải rồi phân tích, chỉ trong một dòng. Đây là mẫu tôi dùng liên tục cho các lượt lấy dữ liệu ngắn gọn.
Dùng cURL trong GitHub Actions và CI/CD
Một bước GitHub Actions tối giản để tải binary với logic retry và báo lỗi rõ ràng:
- name: Download binary
run: |
curl -L --fail --retry 3 --retry-delay 5 \
-o app-binary "https://example.com/releases/app-binary"
Hãy lưu mọi token như CI secrets và tham chiếu bằng biến môi trường — tuyệt đối đừng hardcode vào script. Và nhớ dùng --fail (hoặc --fail-with-body nếu bạn cần xem phần body lỗi để gỡ lỗi) để một lượt tải hỏng thực sự làm hỏng build, thay vì âm thầm thành công với rác.
Câu hỏi bảo mật về curl | sh
Chuyện này gần như xuất hiện trong mọi diễn đàn nhà phát triển tôi từng đọc, và hoàn toàn có lý do: pipe trực tiếp curl vào sh nghĩa là bạn đang chạy code từ xa mà chưa xem qua, chỉ dựa trên niềm tin rằng máy chủ không bị xâm phạm và kết nối không bị can thiệp. Rủi ro thật sự nằm ở đó — không phải hoang tưởng, mà là một vấn đề supply chain rất thẳng thắn.
Mẫu an toàn hơn là tải về trước, xem script, xác minh checksum hoặc chữ ký GPG nếu có, rồi mới chạy:
curl -sL https://example.com/install.sh -o install.sh
cat install.sh # thực sự đọc nội dung
sha256sum install.sh # so với checksum đã công bố nếu có
bash install.sh
Các trình cài đặt nổi tiếng như rustup và Homebrew vẫn dùng mẫu curl | sh, và nhìn chung điều đó được chấp nhận trong những trường hợp cụ thể ấy vì nhà duy trì và kênh phân phối đều rất đáng tin. Tuy vậy, tôi vẫn thà mất thêm 10 giây để xem script còn hơn nhận ra quá muộn rằng mình đã tin nhầm.
Khi cURL không đủ: trang render bằng JS, website chống bot và dữ liệu có cấu trúc
Đây là một kiểu lỗi làm rất nhiều người vấp phải, và thường không phải lỗi của họ: bạn chạy curl -O với một trang trông hoàn toàn bình thường, nhưng thay vì nội dung mong đợi, bạn lại nhận về một khung HTML rỗng, hoặc một trang thử thách của Cloudflare, hoặc thứ gì đó trông như rác. cURL đã làm đúng chức năng của nó — lấy phản hồi HTTP thô — chỉ là nó không thể chạy JavaScript, giải CAPTCHA, hay vượt qua hệ thống nhận diện bot. Đó không phải bug của curl; nó nằm ngoài phạm vi công việc của công cụ này.
Vì sao cURL thất bại với các trang web hiện đại
Nhiều ứng dụng một trang (SPA) hiện đại trả về một khung HTML gần như trống, còn nội dung thật được JavaScript render phía client sau khi trang tải — thứ mà curl không bao giờ thực thi. Bên cạnh đó, các hệ thống như Cloudflare và Akamai chủ động hiển thị trang thử thách cho bất kỳ thứ gì không giống trình duyệt thật, và các request curl lặp lại từ cùng một IP có thể bị giới hạn tốc độ hoặc bị gắn nhãn traffic bot rất nhanh.
Bước tiếp theo: API scraping bằng AI dành cho nhà phát triển
Tôi cho rằng cURL là công cụ đúng cho khoảng 80% trường hợp tải tệp và dữ liệu trên mạng — asset tĩnh, phản hồi API, mọi thứ được phục vụ như tài nguyên HTTP thuần túy. Chính 20% còn lại, tức các trang nặng JavaScript hoặc bị chặn bởi bot, là nơi tôi thấy các nhà phát triển phải vật lộn hàng giờ với header và chuỗi user-agent rồi cuối cùng cũng phải bỏ cuộc để tìm đến một lớp công cụ khác.
Đó chính là khoảng trống mà đội ngũ tôi xây dựng Thunderbit để lấp đầy, bên cạnh tiện ích Chrome mà đa số người dùng đã biết đến. Ở phía dành cho nhà phát triển, Open API của Thunderbit cung cấp POST /distill, trả về Markdown sạch, sẵn cho LLM từ một URL — với phần render trang do dịch vụ xử lý — và POST /extract, trả về JSON có cấu trúc khớp schema khi bạn cần dữ liệu theo trường chứ không chỉ văn bản dễ đọc. Ngoài ra còn có MCP server để các agent trong Claude hoặc Cursor có thể gọi thunderbit_distill và thunderbit_extract ngay trong quá trình làm việc, cùng CLI (npx @thunderbit/thunderbit-cli distill <url>) hoạt động khá giống cURL trong terminal. Ví dụ, bạn có thể pipe đầu ra JSON sang jq, như thunderbit distill <url> --format json | jq -r '.data.markdown'; hoặc dùng đầu ra --format markdown cho công cụ xử lý văn bản hay lưu vào file.
Đặt cạnh nhau, sự khác biệt rất rõ. Một request cURL tới trang sản phẩm render bằng JS có thể chỉ trả về một <div id="root"></div> gần như trống. Còn lệnh thunderbit distill tương ứng sẽ trả về nội dung đã render dưới dạng Markdown sạch. Distill tiêu tốn 1 credit cho mỗi URL và Extract là 20 credit cho mỗi URL. Giới hạn hiện tại theo từng endpoint cũng khác nhau: Batch Distill hỗ trợ tối đa 100 URL cho mỗi job, còn Batch Extract nhận tối đa 50 URL với cùng một schema chung. Hãy kiểm tra tài liệu API hiện tại trước khi ước lượng một hàng đợi production.
Nếu bạn mới làm quen với khái niệm này nói chung, bài giải thích của chúng tôi về web scraping thực sự là gì là điểm khởi đầu khá tốt, và hướng dẫn scraping không cần code sẽ đi vào khía cạnh dành cho người không viết code trong cùng một vấn đề này. Để có cái nhìn so sánh rộng hơn về các công cụ trong lĩnh vực này, chúng tôi cũng có bài tổng hợp những AI web scraper tốt nhất đáng để biết.
Tham khảo nhanh: bảng cheat sheet tải tệp bằng cURL
| Tác vụ | Lệnh |
|---|---|
| Tải cơ bản | curl -LO <url> |
| Tên tệp tùy chỉnh | curl -L -o myfile.zip <url> |
| Tiếp tục tải | curl -C - -LO <url> |
| Im lặng nhưng vẫn hiện lỗi | curl -sSL -O <url> |
| Tải song song | curl --parallel --parallel-max 5 -O <url1> -O <url2> |
| Xác thực bằng bearer token | curl -H "Authorization: Bearer <token>" -LO <url> |
| Lệnh tải nên dùng trong script | curl -LO --retry 5 --retry-delay 3 --max-time 600 --fail <url> |
| Pipe sang công cụ giải nén | curl -sL <url> | tar xz |
Kết luận và các điểm chính cần nhớ
Tải một tệp bằng curl bắt đầu rất đơn giản — curl -O là gần như xong — nhưng kỹ năng thật sự nằm ở các lớp bên dưới: biết khi nào nên thêm -L, khi nào nên tiếp tục thay vì tải lại, kiểu xác thực nào thực sự phù hợp với quy trình của bạn, và phải làm gì ngay khi 403 hoặc một khung HTML rỗng xuất hiện thay vì tệp bạn mong đợi. Tôi đã dựa vào từng mẫu này ở một thời điểm nào đó, thường là ngay sau khi học theo cách rất đau rằng vì sao nó quan trọng.
Đến nay, curl vẫn là công cụ mặc định của tôi cho các lượt tải tệp đơn giản và công việc HTTP có thể script hóa — nhanh, có mặt ở khắp nơi, và kết hợp rất đẹp với phần còn lại của shell pipeline. Nhưng khi bạn gặp một trang render bằng JavaScript hoặc một bức tường chống bot, đó không còn là vấn đề của curl để giải quyết bằng cách thêm vài cờ lệnh nữa; đó là dấu hiệu bạn cần một lớp công cụ khác, và chính ở đó API như của Thunderbit sẽ tiếp quản công việc mà không buộc bạn phải rời khỏi terminal.
Hãy đánh dấu trang cheat sheet, thử lệnh retry-and-resume vào lần tải chập chờn tiếp theo của bạn, và nếu bạn gặp bức tường mà curl chỉ trả về rác, bạn đã biết bước kế tiếp trông như thế nào — trang giá của Thunderbit có bảng credit hiện tại nếu bạn muốn xem việc chuyển cấp đó tốn bao nhiêu, và kênh YouTube của chúng tôi có các video hướng dẫn nếu bạn thích xem hơn là đọc.
Câu hỏi thường gặp về tải tệp bằng cURL
Làm sao để tải tệp bằng cURL và lưu với một tên cụ thể?
Dùng -o rồi đặt tên file bạn muốn: curl -L -o yourname.ext <url>. Thêm -L để chuyển hướng không làm hỏng lượt tải.
Làm sao để tiếp tục một lượt tải cURL bị lỗi?
Chạy curl -C - -LO <url>. Cách này chỉ hoạt động nếu máy chủ hỗ trợ range request — hãy kiểm tra trước bằng curl -I <url> và tìm Accept-Ranges: bytes trong phản hồi.
cURL có thể tải tệp cần đăng nhập không?
Có, theo bốn cách chính: basic auth (-u user:pass), bearer token (-H "Authorization: Bearer <token>"), session dựa trên cookie (-b cookies.txt), hoặc file .netrc cho môi trường script. Xem phần xác thực ở trên để hiểu đầy đủ từng cách và khi nào nên dùng.
Sự khác nhau giữa cURL và wget khi tải tệp là gì?
cURL hỗ trợ nhiều giao thức hơn và thường phù hợp hơn cho scripting, piping, và tải chính xác từng tệp đơn lẻ hoặc số lượng ít. wget được xây dựng cho việc crawl đệ quy và mirror toàn bộ thư mục website, nên là lựa chọn tốt hơn cho việc lấy hàng loạt tệp tĩnh từ site.
Tại sao cURL lại tải trang HTML thay vì file thật?
Thường có hai nguyên nhân: bạn quên cờ -L nên máy chủ đã chuyển hướng sang chỗ khác, hoặc trang đó cần JavaScript để render nội dung thật — thứ mà curl đơn giản là không thể chạy. Trong trường hợp thứ hai, bạn cần một công cụ có khả năng render chứ không phải thêm thêm cờ cho curl.


