Hướng dẫn từng bước để xây dựng máy chủ Proxy Python
Tóm tắt
Một máy chủ proxy Python cần hai đường dẫn mã khác nhau, không phải một. Các yêu cầu HTTP thông thường đến dưới dạng một dòng yêu cầu đầy đủ mà máy chủ có thể chuyển tiếp trực tiếp; các yêu cầu HTTPS đến dưới dạng yêu cầu CONNECT mà máy chủ phải chuyển tiếp một cách mờ đục thay vì phân tích.
asyncio xử lý nhiều kết nối đồng thời mà không có giới hạn một luồng cho mỗi kết nối. Năm yêu cầu đồng thời qua proxy được xây dựng trong hướng dẫn này hoàn thành trong vòng chưa đầy 40ms tổng cộng, với không yêu cầu nào chặn yêu cầu khác.
Phương thức CONNECT là cái làm cho HTTPS hoạt động qua proxy, và đó là bước mà hầu hết các hướng dẫn từ đầu bỏ qua hoặc để chưa kiểm tra — hướng dẫn này triển khai nó và chứng minh nó hoạt động với một trang HTTPS thực.
Thêm hỗ trợ Proxy-Authorization: Basic biến một relay mở thành một relay đã xác thực, và sự khác biệt là có thể kiểm chứng: thông tin xác thực sai hoặc thiếu trả về một 407 thực, thông tin đúng trả về 200.
Một proxy tự lưu trữ có đúng số IP thoát như số máy mà bạn chạy nó trên đó — thường là một. Điều này thì ổn cho phát triển địa phương hoặc một relay trong một khu vực, nhưng đó là giới hạn bạn sẽ gặp phải nếu mục tiêu là phân phối yêu cầu qua nhiều IP.
Không có gì ở đây giải mã hoặc kiểm tra lưu lượng HTTPS. Đường hầm CONNECT chuyển tiếp các byte được mã hóa như là, điều này là hành vi đúng và ít bất ngờ nhất cho một proxy chuyển tiếp cá nhân và tránh phải quản lý chứng chỉ TLS cho việc chặn.
Giới thiệu: viết proxy chuyển tiếp của riêng bạn thay vì chỉ sử dụng một cái
Một proxy chuyển tiếp ngồi giữa khách hàng và internet, chấp nhận các yêu cầu của khách hàng và thực hiện chúng thay mặt cho họ. Xây dựng một cái trong Python thực sự là một bài tập khác biệt so với một proxy từ một đoạn mã Python — chỉ cần chỉ vào cổng của người khác là vài dòng; tạo ra quy trình của riêng bạn để chuyển tiếp đúng cả HTTP thông thường và HTTPS, xử lý nhiều khách hàng cùng một lúc và từ chối việc sử dụng trái phép là nơi mà hầu hết các hướng dẫn từ đầu dừng lại. Hướng dẫn này xây dựng máy chủ đó từ đầu đến cuối trong thư viện tiêu chuẩn của Python, kiểm tra từng đoạn mã với một mục tiêu thực, và trung thực về những giới hạn mà một relay tự lưu trữ thể hiện trong thực tế.
Trải nghiem Nstproxy - Bat dau dung thu mien phi ngay
sử dụng
requests
Cách xây dựng ở đây chỉ sử dụng asyncio, được cung cấp với Python 3.7+ — không cần thêm gói nào cho máy chủ cốt lõi. Mọi thứ đều được xác thực bằng việc chạy nó: mọi đoạn mã bên dưới đều được thực hiện với một máy chủ thử nghiệm cục bộ hoặc một trang HTTPS thực, và các lệnh và kết quả chính xác được hiển thị bên cạnh mã, không chỉ được mô tả. Một proxy tự lưu trữ như thế này cũng là một khối xây dựng phổ biến cho kiểm thử điều kiện mạng và quy trình QA nơi một nhóm muốn có cái nhìn đầy đủ vào và kiểm soát những gì một yêu cầu thực sự làm trước khi nó rời khỏi mạng.
Cài đặt: những gì bạn cần (và không cần)
Máy chủ proxy không có phụ thuộc bên ngoài — asyncio, base64, và sys đều là một phần của thư viện tiêu chuẩn trên bất kỳ cài đặt Python 3.7+ nào. Hai thứ chỉ được sử dụng để kiểm tra, không phải cho chính proxy:
curl, để điều khiển proxy từ dòng lệnh với cờ -x.
Thư viện requests (pip install requests), để xác nhận rằng proxy cũng hoạt động như một khách hàng HTTP Python bình thường mong đợi — sự kết hợp chính xác được gợi ý bởi từ khóa "máy chủ proxy python," mà bao gồm cả việc viết một proxy trong Python và điều khiển một cái từ mã Python.
Không có gì ở đây cần quyền root hoặc hệ điều hành cụ thể; máy chủ liên kết một socket TCP thông thường trên 127.0.0.1 trong các ví dụ, và thay thế bằng 0.0.0.0 (với quy tắc tường lửa giới hạn ai có thể truy cập nó) là thay đổi duy nhất cần thiết để chấp nhận các kết nối từ các máy khác.
Nhìn Lướt Qua
Nếu mục tiêu là định tuyến lưu lượng qua nhiều IP thoát hơn là tìm hiểu cách một proxy hoạt động bên trong, cổng của Nstproxy cung cấp cho bạn một `host:port` đã được tạo sẵn để chỉ định cho các khách hàng HTTP/SOCKS5 thay vì tự duy trì mã relay này.
Một proxy chuyển tiếp cần làm ba điều cho mỗi kết nối: chấp nhận nó, đọc đủ yêu cầu để biết nó đang đi đâu, và chuyển tiếp hoặc relay thích hợp. asyncio.start_server xử lý bước chấp nhận và đưa mỗi kết nối một cặp (reader, writer):
header_lines =[first_line.decode(errors="replace").rstrip("\r\n")]whileTrue: line =await reader.readline()if line in(b"\r\n",b"\n",b""):break header_lines.append(line.decode(errors="replace").rstrip("\r\n")) method, target, _ = header_lines[0].split(" ",2)# phương thức là "CONNECT" cho HTTPS, hoặc "GET"/"POST"/v.v. cho HTTP thông thường
Dòng yêu cầu là điểm phân nhánh: CONNECT host:port HTTP/1.1 có nghĩa là khách hàng muốn một đường hầm HTTPS và không bao giờ có ý định để proxy đọc lưu lượng thực tế của mình; bất kỳ cái gì khác là yêu cầu HTTP thường mà proxy có thể phân tích và chuyển tiếp một cách độc lập.
Triển khai cơ bản: chuyển tiếp yêu cầu HTTP thông thường
Đối với yêu cầu không phải CONNECT, mục tiêu có thể ở trong chính dòng yêu cầu (hình thức tuyệt đối, GET http://host:port/path HTTP/1.1) hoặc trong tiêu đề Host:. Proxy quay số đến đích đó, xây dựng lại yêu cầu mà không có các tiêu đề Proxy-* mà một máy chủ thực sự không mong đợi, và chuyển bytes theo cả hai hướng:
Bên trong handle_client, nhánh không phải CONNECT phân tích mục tiêu và xây dựng lại yêu cầu:
if target.startswith("http://"): rest = target[len("http://"):] host_port, _, path = rest.partition("/") path ="/"+ path
else: path = target
host_port =next((h.split(":",1)[1].strip()for h in header_lines[1:]if h.lower().startswith("host:")),None,)host, _, port = host_port.partition(":")port =int(port or80)remote_reader, remote_writer =await asyncio.open_connection(host, port)rebuilt =f"{method}{path} HTTP/1.1\r\n"for h in header_lines[1:]:ifnot h.lower().startswith("proxy-"): rebuilt += h +"\r\n"rebuilt +="\r\n"remote_writer.write(rebuilt.encode())await remote_writer.drain()await asyncio.gather(pipe(remote_reader, writer), pipe(reader, remote_writer))
Được kiểm tra với một máy chủ HTTP cục bộ tạm thời (http.server, gán vào 127.0.0.1:9000, trả về một nội dung cố định) với proxy lắng nghe trên 127.0.0.1:8080:
Điều đó đã trả về nội dung hello-from-local-target và HTTP_STATUS:200. Đã xác nhận với curl -v rằng yêu cầu thực sự đã đi qua proxy (> GET http://127.0.0.1:9000/ HTTP/1.1 được gửi đến cổng 8080, phản hồi được chuyển tiếp lại) thay vì curl kết nối trực tiếp đến mục tiêu — một rủi ro thực sự trong bất kỳ môi trường thử nghiệm nào mà thiết lập no_proxy có thể im lặng bỏ qua proxy cho một số máy chủ nhất định, vì vậy xác minh con đường thực tế đã qua quan trọng hơn nhiều so với việc chỉ tin tưởng vào mã trạng thái cuối cùng.
Các mẫu nâng cao: Đường hầm HTTPS, xác thực và đồng thời
Đường hầm HTTPS với CONNECT
Một proxy chỉ xử lý trường hợp trên không thể mang lưu lượng HTTPS — khách hàng sắp bắt đầu một bước bắt tay TLS với đích đến, và proxy không có quyền (hoặc khả năng, thiếu khóa riêng cho trang web mục tiêu) để kiểm tra điều đó. Giải pháp là phương thức CONNECT: proxy mở một kết nối TCP thô đến host:port đã yêu cầu, trả về 200 Connection Established, và từ đó trở đi chỉ chuyển bytes theo cả hai hướng mà không quan tâm đến chúng:
if method =="CONNECT": host, _, port = target.partition(":") port =int(port or443) remote_reader, remote_writer =await asyncio.open_connection(host, port) writer.write(b"HTTP/1.1 200 Connection Established\r\n\r\n")await writer.drain()await asyncio.gather( pipe(reader, remote_writer), pipe(remote_reader, writer),)
Đây là cơ chế chính xác mà tài liệu tham khảo phương thức CONNECT của MDN mô tả: "phương thức HTTP CONNECT yêu cầu một proxy thiết lập một đường hầm HTTP đến một máy chủ đích, và nếu thành công, chuyển tiếp dữ liệu một cách mù quáng theo cả hai hướng cho đến khi đường hầm bị đóng." Đã được kiểm tra với một trang HTTPS thực (không phải mô phỏng) qua proxy trên cổng 8080:
curl -v trên cùng một lệnh đã xác nhận đường dẫn đầy đủ: CONNECT pypi.org:443 sent đến proxy, 200 Kết nối đã được thiết lập được trả về, sau đó là SSL kết nối sử dụng TLSv1.3 / TLS_AES_256_GCM_SHA384, và cuối cùng là phản hồi HTTP/2 200 từ chính pypi.org — quá trình bắt tay TLS diễn ra từ đầu đến cuối giữa curl và pypi.org thông qua đường hầm, với proxy không bao giờ thấy văn bản bPlain. URL tương tự cũng hoạt động từ thư viện requests của Python chỉ định vào proxy thông qua proxies={"http": "http://127.0.0.1:8080", "https": "http://127.0.0.1:8080"}, trả về 200 và JSON hợp lệ — xác nhận rằng máy chủ hoạt động giống như một proxy cho một thư viện khách HTTP thực sự, không chỉ cho curl.
Yêu cầu xác thực
Một relay mở trên internet công cộng nhanh chóng bị lạm dụng. Thêm xác thực cơ bản có nghĩa là kiểm tra tiêu đề Proxy-Authorization trước khi thực hiện bất kỳ chuyển tiếp nào, và trả về 407 (tương đương cụ thể của proxy đối với 401) khi nó thiếu hoặc sai:
import base64
AUTH = base64.b64encode(b"devuser:s3cret").decode()# thường được tải từ cấu hình, không được mã hóa cứngdefcheck_auth(headers:list[str])->bool:for h in headers:if h.lower().startswith("proxy-authorization:"): value = h.split(":",1)[1].strip()if value.startswith("Basic "):return value[len("Basic "):].strip()== AUTH
returnFalseasyncdefsend_407(writer: asyncio.StreamWriter): body =b"Yêu cầu xác thực Proxy" writer.write(b"HTTP/1.1 407 Yêu cầu xác thực Proxy\r\n"b'Proxy-Authenticate: Basic realm="proxy"\r\n'b"Content-Length: "+str(len(body)).encode()+b"\r\n"b"Connection: close\r\n\r\n"+ body
)await writer.drain() writer.close()
Kết quả trực tiếp với máy chủ có xác thực trên cổng 8081:
Yêu cầu
Kết quả
Không có tiêu đề Proxy-Authorization
407 Yêu cầu xác thực Proxy
Thông tin đăng nhập sai (devuser:wrongpass)
407 Yêu cầu xác thực Proxy
Thông tin đăng nhập chính xác, mục tiêu HTTP thuần túy
200, nội dung được chuyển tiếp chính xác
Thông tin đăng nhập chính xác, mục tiêu HTTPS qua CONNECT
200
Cả hai trường hợp lỗi đều được tái hiện bằng cách thực sự gửi thông tin đăng nhập sai hoặc không có, chứ không phải từ việc đọc mã — cùng một kỷ luật mà dự án này áp dụng cho mọi tuyên bố cấu hình proxy mà nó công bố.
Đối tượng đồng thời mà không cần một luồng cho mỗi kết nối
Bởi vì handle_client là một coroutine, vòng lặp sự kiện của asyncio chạy nhiều kết nối đồng thời trên một luồng duy nhất thay vì tạo một luồng hệ điều hành cho mỗi khách hàng, đây là mẫu hầu hết các hướng dẫn proxy từ đầu sử dụng. Năm yêu cầu đồng thời thông qua cùng một phiên bản proxy đang chạy:
Điều đó đã in ra req1:200 req2:200 req3:200 req4:200 req5:200 và thực tế 0m0.033s. Tất cả năm yêu cầu đã hoàn thành trong 33 mili giây mà không có yêu cầu nào chờ đợi yêu cầu khác — hành vi được tài liệu hóa cho các API luồng của asyncio, nơi hồi ngoặt của start_server chạy một lần cho mỗi kết nối như một coroutine độc lập thay vì một cuộc gọi chặn.
Mọi thứ ở trên là một proxy có tác dụng thực, đang hoạt động — và nó vẫn có những giới hạn đáng biết trước khi dựa vào nó cho bất cứ điều gì ngoài phát triển cục bộ hoặc một relay đơn vùng.
Cái cụ thể nhất xuất hiện ngay khoảnh khắc một trang web mục tiêu bắt đầu chặn IP của proxy: máy chủ này chỉ có một IP đầu ra, địa chỉ của máy mà nó đang chạy, vì vậy khi bị chặn, mọi khách hàng phía sau nó cũng sẽ bị chặn cho đến khi IP đó thay đổi. Đó là lúc mà một cổng xoay vòng trở thành công cụ trực tiếp hơn cho công việc này so với máy chủ được xây dựng trong hướng dẫn này — dòng Residential Lite của Nstproxy chạy nhiều IP đầu ra độc lập từ cư dân phía sau một host:port duy nhất, sử dụng cùng một định dạng kết nối client HTTP/SOCKS5 được ghi tài liệu cho cổng, vì vậy một yêu cầu có thể bị kẹt trên một IP bị chặn sẽ được gửi đi trên một IP khác, và mã phía khách hàng không cần biết rằng đã có một lượt xoay vòng. Nó được tính theo mô hình trả trước, pay-as-you-go trên trang giá Residential Lite thay vì một đăng ký cố định, và được thiết kế cho các script và dịch vụ cần phân phối lưu lượng truy cập trên một bể IP lớn, đa dạng về địa lý (hơn 200 quốc gia và vùng lãnh thổ, theo giải thích của Nstproxy về cách các proxy HTTP hoạt động) thay vì cho các đội ngũ muốn sở hữu và sửa đổi mã relay — nếu kiểm tra hoặc ghi lại lưu lượng ở lớp proxy là mục tiêu thực tế, một máy chủ tự lưu trữ như cái ở trên vẫn là công cụ đúng đắn, và một cổng xoay vòng là một bước nhảy bổ sung phía trên, không phải là sự thay thế cho nó.
Bể IP đầu ra lớn, phân phối — nhiều IP độc lập từ cư dân phía sau cổng có nghĩa là một IP bị chặn hoặc bị giới hạn tốc độ không làm kẹt toàn bộ công việc như nó sẽ làm trên một địa chỉ duy nhất của máy chủ tự lưu trữ này.
Hình thức giao thức cùng phía khách hàng — cổng phát ngôn HTTP, HTTPS và SOCKS5 trên một đầu cuối, vì vậy mã được viết theo proxy của hướng dẫn này (hoặc theo từ điển proxies của requests) sẽ chỉ vào cổng với cùng một mã kết nối, chỉ là một host:port khác.
Khu vực đầu ra toàn cầu — hữu ích khi nội dung, khả năng truy cập hoặc giới hạn tốc độ của một trang web mục tiêu khác nhau theo vị trí yêu cầu, mà một máy chủ tự lưu trữ duy nhất không thể sao chép mà không triển khai một instance ở mỗi vùng.
Hai điều mà xây dựng này cố tình không làm, và không nên được coi là có thể làm mà không có thêm công việc: nó không giải mã hoặc kiểm tra các payload HTTPS (đường hầm CONNECT là mờ đục theo thiết kế, điều này là đúng cho một relay cá nhân và tránh quản lý chứng chỉ TLS cho việc chặn), và nó không lưu trữ nhật ký, không giới hạn tốc độ khách hàng, hay thi hành danh sách truy cập ngoài thông tin xác thực Basic-auth duy nhất được hiển thị — một proxy được công khai ngoài 127.0.0.1 cần ít nhất thông tin xác thực và giới hạn kết nối cho từng khách hàng trước khi nó an toàn để chạy không giám sát.
Khắc phục sự cố lỗi thường gặp
curl: (7) Không thể kết nối gần như luôn có nghĩa là quá trình proxy không đang lắng nghe trên địa chỉ/cánh cổng mà curl đã cung cấp, hoặc một tường lửa đang chặn cổng đó — xác nhận với ss -tlnp | grep <cổng> rằng thứ gì đó thực sự được kết nối ở đó trước khi kiểm tra mã proxy.
Một yêu cầu dường như thành công ngay cả khi cổng proxy sai, hoặc thông tin xác thực sai dường như có hiệu lực — kiểm tra xem no_proxy/NO_PROXY có được thiết lập trong môi trường shell và bao gồm máy chủ mục tiêu; một số môi trường sandboxed và CI mặc định thiết lập điều này, và curl hoặc requests sẽ hoàn toàn bỏ qua proxy đã cấu hình cho bất kỳ máy chủ nào trong danh sách đó. Chạy env -u no_proxy -u NO_PROXY trước lệnh kiểm tra để loại trừ điều này, và xác nhận với curl -v rằng dòng yêu cầu hiển thị cổng của proxy, không phải một kết nối trực tiếp.
502 Bad Gateway từ proxy này có nghĩa là proxy không thể đạt được máy chủ đích — kiểm tra xem tên máy chủ mục tiêu có giải quyết được hay không và cổng có thể truy cập từ máy đang chạy proxy, chứ không phải từ khách hàng.
HTTPS hoạt động nhưng HTTP bình thường không hoạt động (hoặc ngược lại) — điều này gần như luôn liên quan đến nhánh dòng yêu cầu: xác nhận rằng khách hàng thực sự đang gửi CONNECT cho HTTPS (một số thư viện client HTTP cần một mục proxy https rõ ràng, tách biệt khỏi http, trước khi chúng làm điều này) và một dòng yêu cầu dạng tuyệt đối hoặc một header Host: cho HTTP bình thường.
Kết luận
Một máy chủ proxy Python hoạt động phụ thuộc vào hai hình dạng yêu cầu được xử lý khác nhau — HTTP bình thường được chuyển tiếp và xây dựng lại, HTTPS được hầm mờ qua CONNECT — cộng với bất kỳ xác thực và xử lý đồng thời nào mà triển khai thực sự cần. Mỗi phần của điều đó, bao gồm các phần mà hầu hết các hướng dẫn nhanh bỏ qua (một đường hầm HTTPS thực sự, một 407 thực sự, các yêu cầu đồng thời thực sự), đã được chạy chống lại một mục tiêu trực tiếp trong hướng dẫn này thay vì được mô tả từ trí nhớ. Điểm mà trần IP đầu ra duy nhất của xây dựng này trở thành nút thắt thực sự là điểm cần lựa chọn một cổng xoay vòng được quản lý thay vì mở rộng mã này thêm nữa.
H: Một máy chủ proxy Python bạn tự xây dựng có thể xử lý lưu lượng HTTPS không?
Có, nhưng chỉ bằng cách thực hiện phương thức CONNECT và chuyển tiếp các byte mã hóa mà không kiểm tra chúng — một proxy chỉ phân tích các dòng yêu cầu HTTP thông thường (phiên bản hướng dẫn đầu tiên phổ biến) không thể truyền tải HTTPS, vì máy khách không bao giờ gửi yêu cầu thực tế của đích đến qua đó dưới dạng văn bản rõ.
H: Chạy máy chủ proxy riêng có hợp pháp không?
Chạy một máy chủ proxy là hợp pháp; điều quan trọng là nó được sử dụng cho mục đích gì và liệu lưu lượng đi qua đó có được ủy quyền hay không — việc sử dụng proxy tự xây dựng hoặc của bên thứ ba để vượt qua các biện pháp kiểm soát truy cập, thu thập dữ liệu trái với điều khoản của một trang web hoặc ẩn giấu hoạt động bất hợp pháp mang theo rủi ro pháp lý bất kể mã nào đang thực hiện việc chuyển tiếp.
H: Tại sao một proxy cần hỗ trợ phương thức CONNECT cụ thể, thay vì chỉ chuyển tiếp các yêu cầu HTTPS như các yêu cầu HTTP?
Bởi vì một yêu cầu HTTPS được mã hóa trước khi rời khỏi máy khách, vì vậy một proxy xử lý nó theo cách như nó xử lý HTTP thông thường sẽ cần thấy văn bản rõ mà nó không bao giờ nhận được; CONNECT tránh điều đó bằng cách để proxy chuyển tiếp các byte một cách mù quáng sau khi đường hầm được mở, vì vậy việc bắt tay TLS xảy ra trực tiếp giữa máy khách và đích đến thực tế.
H: Máy chủ proxy bạn tự xây dựng khác gì với dịch vụ proxy xoay vòng thương mại?
Một máy chủ tự lưu trữ như trong hướng dẫn này có số lượng IP thoát chính xác bằng số máy nó chạy trên — thường là một — trong khi một cổng xoay vòng thương mại ngồi trước một nhóm IP lớn, được quản lý và thay đổi cái nào xử lý mỗi yêu cầu, điều này quan trọng khi việc chặn dựa trên IP hoặc giới hạn tỷ lệ (không phải độ phức tạp của mã) trở thành hạn chế thực tế.
H: Proxy này có hoạt động với thư viện requests của Python, hay chỉ với curl?
Cả hai — máy chủ nói chuyện bằng proxy HTTP thông thường và đường hầm CONNECT ở cấp độ giao thức, vì vậy bất kỳ máy khách nào thực hiện điều đó một cách chính xác, bao gồm cả requests qua tham số proxies, curl -x, và các trình duyệt, đều có thể sử dụng mà không cần xử lý đặc biệt.
Các trình phân tích PDF tốt nhất cho quy trình làm việc AI và RAG vào năm 2026
Một so sánh đã được nghiên cứu và kiểm tra bằng chứng về các trình phân tích PDF tốt nhất cho các pipeline AI và RAG vào năm 2026 — LlamaParse, Docling, Marker, Unstructured, Reducto, Firecrawl, PyMuPDF4LLM và các API tài liệu AI lớn của các hyperscaler — được xếp hạng dựa trên OCR, trích xuất bảng và chi phí, cộng với cái nhìn trung thực về vị trí của Nstproxy Crawl (và không) trong một pipeline dữ liệu RAG.
Marcus Chen
Aug. 17th 2026
110M+ IP that voi ti le truy cap thanh cong 99.9%
Phan hoi trung binh ~0.5s cho tac vu dong thoi cao
Chi tu $0.1/GB
Truy cap ngay cac pool proxy residential, datacenter, IPv6 va ISP cao cap.