← Quay lại blog

WebSocket, gRPC, HTTP/2 qua proxy: cách chọn giao thức cho stack của bạn

Phân tích đặc điểm của việc proxy WebSocket, gRPC và HTTP/2 - chọn giao thức nào, cách cấu hình máy chủ proxy và tránh những lỗi thường gặp của lập trình viên.

📅21 tháng 9, 2026

Khi làm việc với proxy, các nhà phát triển thường gặp phải vấn đề rằng các thiết lập proxy HTTP cổ điển không hoạt động cho các kết nối WebSocket, và gRPC thì hoàn toàn bị lỗi với các lỗi TLS handshake. Vấn đề là WebSocket, HTTP/2 và gRPC không chỉ là "các biến thể của HTTP", mà là các mô hình vận chuyển khác nhau với các yêu cầu riêng về tunneling, multiplexing và xử lý tiêu đề. Trong bài viết này, chúng ta sẽ phân tích cách proxy cho từng giao thức này, những cạm bẫy thường gặp trong thực tế và cách chọn giao thức và loại proxy cho từng nhiệm vụ cụ thể — từ phân tích qua WebSocket đến các microservices gRPC có tải cao.

Các giao thức khác nhau như thế nào và tại sao điều này quan trọng cho proxy

HTTP/1.1 hoạt động theo mô hình "yêu cầu - phản hồi": máy khách mở kết nối, gửi yêu cầu, nhận phản hồi và hoặc đóng kết nối, hoặc giữ nó mở cho yêu cầu tiếp theo (keep-alive). Các máy chủ proxy đã được tối ưu hóa trong nhiều thập kỷ cho mô hình này — phân tích tiêu đề, bộ đệm nội dung yêu cầu, định tuyến đơn giản theo tiêu đề Host.

WebSocket phá vỡ mô hình này: sau khi thực hiện HTTP handshake ban đầu (Upgrade: websocket), kết nối trở thành một kênh hai chiều liên tục, nơi dữ liệu có thể đi theo cả hai hướng bất kỳ lúc nào. Proxy phải "thả" kết nối này và chỉ cần chuyển byte qua lại, không cố gắng diễn giải chúng như các yêu cầu HTTP.

HTTP/2 thêm multiplexing — nhiều yêu cầu logic đi qua một kết nối TCP song song, sử dụng các khung nhị phân thay vì các tiêu đề văn bản. Đối với proxy, điều này có nghĩa là không thể chỉ đọc văn bản theo dòng — cần hỗ trợ giao thức nhị phân HTTP/2 ở mức proxy hoặc tunneling TCP trong suốt qua TLS.

gRPC đi xa hơn nữa: nó được xây dựng hoàn toàn trên HTTP/2, sử dụng Protocol Buffers để tuần tự hóa và yêu cầu một phương tiện tương thích với HTTP/2 trên toàn bộ đường đi từ máy khách đến máy chủ. Nếu proxy ở một số đoạn "giảm cấp" kết nối xuống HTTP/1.1, yêu cầu gRPC sẽ không được thực hiện.

Hiểu những sự khác biệt này là rất quan trọng, vì việc chọn sai loại proxy hoặc cấu hình không chính xác tunneling dẫn đến ngắt kết nối, timeout và các lỗi khó giải thích, mà khó chẩn đoán nếu không hiểu rõ về cấp độ vận chuyển.

WebSocket qua proxy: cấu hình và mã

Đối với WebSocket qua proxy, có hai kịch bản chính: proxy HTTP với phương thức CONNECT (cho WSS, tức là WebSocket qua TLS) và proxy SOCKS5, cái mà tunneling kết nối TCP mà không phân tích giao thức. SOCKS5 thường ít vấn đề hơn, vì nó được thiết kế ban đầu như một "ống trong suốt" cho bất kỳ lưu lượng TCP nào.

Ví dụ về kết nối đến WebSocket qua proxy SOCKS5 trên Python với thư viện websockets và python-socks:

import asyncio
from python_socks.sync import Proxy
import websockets
import websockets.sync.client as ws_client

def connect_ws_via_proxy():
    proxy = Proxy.from_url("socks5://user:pass@proxy_host:1080")
    sock = proxy.connect(dest_host="echo.websocket.events", dest_port=443)

    ws = ws_client.connect(
        "wss://echo.websocket.events",
        sock=sock,
        server_hostname="echo.websocket.events"
    )
    ws.send("Hello via proxy")
    print(ws.recv())
    ws.close()

connect_ws_via_proxy()

Trên Node.js, nhiệm vụ tương tự được giải quyết thông qua gói ws kết hợp với socks-proxy-agent:

const WebSocket = require('ws');
const { SocksProxyAgent } = require('socks-proxy-agent');

const agent = new SocksProxyAgent('socks5://user:pass@proxy_host:1080');
const socket = new WebSocket('wss://echo.websocket.events', { agent });

socket.on('open', () => socket.send('Hello via proxy'));
socket.on('message', (data) => console.log(data.toString()));

Nếu proxy chỉ khả dụng qua HTTP (với phương thức CONNECT), sơ đồ tương tự — hầu hết các máy khách WebSocket hiện đại đều có thể hoạt động qua đường hầm HTTP, chỉ cần đảm bảo rằng proxy không ngắt các kết nối lâu dài do timeout. Đây là một vấn đề thường gặp với các proxy trung tâm dữ liệu giá rẻ, mà có giới hạn cứng từ 30-60 giây cho kết nối không hoạt động — đối với các nhiệm vụ WebSocket streaming, điều này là rất quan trọng, và tốt hơn là xác minh các tham số keep-alive với nhà cung cấp.

HTTP/2 qua proxy: multiplexing và cạm bẫy

Khó khăn chính với HTTP/2 qua proxy là nhiều máy chủ proxy (đặc biệt là Squid cũ hoặc proxy chuyển tiếp đơn giản) chỉ hoạt động với HTTP/1.1 và tự động "giảm cấp" kết nối. Đối với máy khách, điều này thường không đáng chú ý (yêu cầu vẫn được thực hiện), nhưng mất đi lợi ích của multiplexing — độ trễ tăng lên, đặc biệt là khi có nhiều yêu cầu song song đến một máy chủ.

Để kiểm tra xem kết nối qua proxy có hỗ trợ HTTP/2 hay không, bạn có thể sử dụng cURL với cờ --http2 và đầu ra chi tiết:

curl -v --http2 -x http://user:pass@proxy_host:8080 https://example.com

# Trong đầu ra, tìm dòng:
# * Using HTTP2, server supports multiplexing
# Nếu không có nó — kết nối đã giảm xuống HTTP/1.1

Trên Python, để sử dụng HTTP/2 qua proxy, cần thư viện httpx với hỗ trợ HTTP/2 được bật:

import httpx

proxies = {
    "http://": "http://user:pass@proxy_host:8080",
    "https://": "http://user:pass@proxy_host:8080",
}

with httpx.Client(proxies=proxies, http2=True) as client:
    response = client.get("https://example.com")
    print(response.http_version)  # mong đợi "HTTP/2"
    print(response.status_code)

Một điểm quan trọng: HTTP/2 yêu cầu TLS với mở rộng ALPN để đồng bộ hóa giao thức, vì vậy proxy phải tunneling lưu lượng TLS một cách trong suốt qua CONNECT, thay vì tự kết thúc TLS (nếu không phải là một proxy tương thích với HTTP/2 chuyên dụng). Chính vì vậy, cho các nhiệm vụ với HTTP/2, các proxy cư trú và proxy trung tâm dữ liệu hoạt động khác nhau — quan trọng là xác minh với nhà cung cấp xem có hỗ trợ tunneling TLS xuyên suốt mà không làm gián đoạn các cuộc thương lượng ALPN hay không.

gRPC qua proxy: TLS, ALPN và các yêu cầu đặc biệt

gRPC là giao thức yêu cầu nhất trong bộ này. Nó hoàn toàn phụ thuộc vào HTTP/2 và thường sử dụng TLS hai chiều (mTLS) để xác thực. Một proxy chuyển tiếp thông thường, không hỗ trợ HTTP/2 CONNECT tunneling "như là", sẽ không cho phép lưu lượng gRPC đi qua — kết nối sẽ bị lỗi với các lỗi như UNAVAILABLE: upstream connect error.

Để proxy gRPC trên Python (với thư viện grpc) proxy được chỉ định qua các biến môi trường, vì không có hỗ trợ tích hợp cho proxy trong tùy chọn kênh từ trước đến nay:

import os
import grpc

os.environ["grpc_proxy"] = "http://user:pass@proxy_host:8080"
os.environ["https_proxy"] = "http://user:pass@proxy_host:8080"

channel = grpc.secure_channel(
    "grpc.example.com:443",
    grpc.ssl_channel_credentials()
)

# Ví dụ về việc gọi qua stub được tạo
# stub = YourServiceStub(channel)
# response = stub.YourMethod(request)

Trên Node.js, proxy cho gRPC được cấu hình thông qua các tùy chọn kênh grpc-js kết hợp với một proxy agent tương thích với HTTP/2:

const grpc = require('@grpc/grpc-js');
const { HttpsProxyAgent } = require('https-proxy-agent');

process.env.grpc_proxy = 'http://user:pass@proxy_host:8080';
process.env.https_proxy = 'http://user:pass@proxy_host:8080';

const client = new YourServiceClient(
  'grpc.example.com:443',
  grpc.credentials.createSsl()
);

Để gRPC hoạt động ổn định qua proxy, độ trễ thấp và kết nối TCP ổn định là rất quan trọng mà không bị ngắt kết nối thường xuyên — các luồng gRPC multiplexed nhạy cảm hơn với sự cố mạng so với các yêu cầu HTTP/1.1 riêng lẻ. Trong các kịch bản như vậy, các proxy cư trú thường cho thấy độ ổn định tốt hơn so với các bể trung tâm dữ liệu giá rẻ, vì đường đi đến máy chủ đích đi qua cơ sở hạ tầng mạng dễ đoán hơn.

Bảng so sánh các giao thức

Giao thức Loại kết nối Yêu cầu cho proxy Loại proxy được khuyến nghị
HTTP/1.1 yêu cầu-phản hồi, keep-alive tối thiểu, bất kỳ proxy HTTP nào Proxy trung tâm dữ liệu
WebSocket kênh hai chiều liên tục hỗ trợ kết nối lâu dài, không có timeout Proxy cư trú
HTTP/2 các luồng nhị phân multiplexed tunneling TLS xuyên suốt, ALPN Proxy cư trú hoặc trung tâm dữ liệu
gRPC HTTP/2 + Protobuf, thường là mTLS độ trễ thấp, độ ổn định, HTTP/2 CONNECT Proxy di động để vượt qua các bộ lọc nghiêm ngặt

Cách chọn giao thức và proxy cho ngăn xếp của bạn

Việc chọn giao thức hiếm khi là một quyết định tự do — nó được quy định bởi API mục tiêu. Nhưng việc chọn loại proxy cho giao thức này — đó là trách nhiệm của bạn, và ở đây bạn nên dựa vào kịch bản cụ thể:

Phân tích dữ liệu qua WebSocket (ví dụ, streaming báo giá hoặc dữ liệu real-time từ các trang web marketplace) yêu cầu một kết nối ổn định lâu dài mà không bị ngắt kết nối do timeout. Ở đây, proxy cư trú hoạt động tốt hơn — chúng ít bị rơi vào các thuật toán chống gian lận của dịch vụ mục tiêu và giữ kết nối lâu hơn so với các bể trung tâm dữ liệu điển hình.

Tích hợp với các microservices gRPC qua proxy bên ngoài (ví dụ, khi kiểm tra API từ các vị trí địa lý khác nhau) yêu cầu độ trễ thấp và hỗ trợ HTTP/2 trên toàn bộ đường đi. Đối với điều này, các IP cư trú với định tuyến tốt là phù hợp, và cho các nhiệm vụ nhạy cảm về thời gian — proxy di động, nếu dịch vụ mục tiêu lọc các dải trung tâm dữ liệu một cách quyết liệt.

Các yêu cầu HTTP/2 hàng loạt đến REST/GraphQL API với multiplexing — là kịch bản thường gặp nhất, nơi mà các proxy trung tâm dữ liệu nhanh và rẻ là đủ, nếu dịch vụ mục tiêu không chặn các dải IP trung tâm dữ liệu theo mặc định.

Quy tắc chung: càng "khó tính" giao thức đối với độ ổn định của kết nối (WebSocket, gRPC), càng có nhiều ý nghĩa trong việc sử dụng IP cư trú hoặc di động. Càng đơn giản và ngắn gọn yêu cầu (HTTP/1.1 thông thường hoặc HTTP/2 mà không có các phiên dài), càng thoải mái hơn khi làm việc với các proxy trung tâm dữ liệu — chúng nhanh hơn và cung cấp băng thông cao hơn.

Các lỗi thường gặp và giải pháp của chúng

Lỗi 1: WebSocket bị ngắt kết nối mỗi 30-60 giây. Nguyên nhân — proxy hoặc bộ cân bằng trung gian đóng các kết nối "không hoạt động". Giải pháp: bật các khung ping/pong ở cấp độ ứng dụng với khoảng thời gian ngắn hơn timeout của proxy (thường 20-25 giây là đủ).

Lỗi 2: gRPC bị lỗi UNAVAILABLE qua proxy, mặc dù hoạt động trực tiếp. Proxy không hỗ trợ tunneling HTTP/2 CONNECT. Giải pháp: kiểm tra tài liệu của nhà cung cấp về việc hỗ trợ HTTP/2, hoặc sử dụng proxy SOCKS5, cái mà tunneling TCP mà không diễn giải giao thức.

Lỗi 3: HTTP/2 không rõ ràng giảm cấp xuống HTTP/1.1. Điều này thường xảy ra do thiếu hỗ trợ ALPN trên proxy. Hãy kiểm tra rõ ràng phiên bản giao thức trong mã (như trong ví dụ với httpx ở trên) — đừng dựa vào việc "mọi thứ hoạt động", nếu bạn không kiểm tra http_version trong phản hồi.

Lỗi 4: Độ trễ cao khi multiplexing gRPC qua proxy. Thường do số lượng nút trung gian lớn của nhà cung cấp proxy. Giải pháp: kiểm tra độ trễ trước thông qua một yêu cầu RTT đơn giản và chọn nhà cung cấp với định tuyến trực tiếp, đặc biệt cho các cuộc gọi gRPC nhạy cảm về thời gian.

Kết luận

WebSocket, HTTP/2 và gRPC yêu cầu cách tiếp cận khác nhau trong việc cấu hình proxy chính vì chúng hoạt động trên các mô hình vận chuyển khác nhau: từ việc đơn giản "thả kết nối TCP" cho WebSocket đến việc hỗ trợ nghiêm ngặt HTTP/2 CONNECT và ALPN cho gRPC. Hãy kiểm tra rõ ràng phiên bản giao thức trong mã, kiểm tra độ ổn định của các kết nối lâu dài trước và chọn SOCKS5 ở những nơi cần tối đa tính minh bạch của tunneling.

Nếu ngăn xếp của bạn bao gồm các kết nối WebSocket lâu dài hoặc các cuộc gọi gRPC nhạy cảm với độ trễ, chúng tôi khuyên bạn nên thử proxy cư trú — chúng cung cấp các kết nối ổn định và dự đoán hơn so với các bể trung tâm dữ liệu điển hình. Đối với các yêu cầu HTTP/2 đơn giản với băng thông cao, các proxy trung tâm dữ liệu là phù hợp, và cho các nhiệm vụ với bộ lọc chống gian lận quyết liệt của dịch vụ mục tiêu — proxy di động.