Ngiêm cấm sử đụng PROXY và VPS vào mục đích trái pháp luật bạn sẽ phải chịu toàn bộ trách nhiệm trước pháp luật khi sử dụng dịch vụ của chúng tôi tks!
Ktor Client proxy: chọn engine, cấu hình và xác thực proxy

Ktor Client proxy: chọn engine, cấu hình và xác thực proxy

Chuyên viên Kỹ thuật ProxyVN 07-23-2026 Đang tính... phút đọc

Ktor Client proxy là cách cho HttpClient của Ktor gửi request qua máy trung gian. Với Ktor, proxy không phải một tùy chọn chung mà phụ thuộc engine bên dưới: CIO, OkHttp, Java, Apache hay Darwin. ProxyVN đối chiếu tài liệu Ktor 3.6.0, lập bảng engine nào làm được gì và chỉ ra chỗ xác thực proxy dễ trượt khi gọi HTTPS.

Ktor Client proxy phụ thuộc vào engine

Proxy phụ thuộc engine

Proxy phụ thuộc engine

Ktor là lớp API, engine mới là tầng mạng

Ktor Client là thư viện HTTP đa nền tảng của JetBrains viết bằng Kotlin. Mã gọi request của anh em giống nhau trên JVM, Android, iOS hay JavaScript. Nhưng việc mở kết nối, bắt tay TLS và nói chuyện với proxy do engine đảm nhiệm. Mỗi engine là một client HTTP khác nhau được bọc lại.

Hệ quả là cùng một dòng cấu hình proxy có thể chạy trên engine này nhưng bị bỏ qua trên engine khác. Bảng hỗ trợ trong tài liệu proxy của Ktor ghi rõ Jetty và JavaScript không hỗ trợ proxy, còn SOCKS chỉ có ở Android, OkHttp, Darwin và Curl.

Trước khi viết dòng cấu hình proxy đầu tiên, anh em cần biết project đang dùng engine nào. Câu trả lời quyết định giao thức proxy dùng được và cách xác thực.

Ranh giới với bài Java proxy

Bài Java proxy nói về proxy toàn JVM qua system properties và ProxySelector. Những thiết lập đó có thể ảnh hưởng tới engine Java của Ktor, nhưng không dạy API của Ktor. Bài này chỉ đi vào ProxyBuilder, khối engine, bảng hỗ trợ theo engine và cách xác thực theo tài liệu Ktor.

Nếu anh em gọi API từ Android bằng OkHttp thuần, không qua Ktor, hướng dẫn của OkHttp sẽ phù hợp hơn. Bài này dành cho project đã chọn Ktor Client và cần đưa request qua proxy một cách có kiểm chứng.

Phạm vi kiểm thử

Máy lab của ProxyVN hôm viết bài không có trình biên dịch Kotlin, Gradle hay JDK 11 trở lên, chỉ có JRE 8. Vì vậy mã trong bài chưa được biên dịch và chạy trên máy này. Mình viết theo tài liệu Ktor 3.6.0 và tài liệu của các client bên dưới.

Cuối bài có bộ ca kiểm để anh em tự chạy với proxy cục bộ. Kết quả thực tế trên đúng engine và phiên bản của anh em là chuẩn cuối cùng, không phải mô tả trong bài.

Bảng hỗ trợ Ktor Client proxy theo engine

Bảng từ tài liệu chính thức

Bảng dưới chép từ tài liệu proxy của Ktor. Tài liệu không có cột riêng cho proxy HTTPS, tức kết nối tới chính proxy bằng TLS.

Bảng: Bảng từ tài liệu chính thức

Engine

Proxy HTTP

Proxy SOCKS

Apache

Có

Không

Java

Có

Không

Jetty

Không

Không

CIO

Có

Không

Android

Có

Có

OkHttp

Có

Có

JavaScript

Không

Không

Darwin

Có

Có

Curl

Có

Có

Tài liệu có thêm một ghi chú: engine Darwin hiện không hỗ trợ request HTTPS qua proxy HTTP. Với ứng dụng iOS dùng Darwin, đây là giới hạn lớn vì gần như mọi API đều dùng HTTPS.

Đọc bảng theo nhu cầu thật

Bảng cho biết engine có nhận cấu hình proxy hay không, nhưng không nói gì về xác thực. Proxy thương mại hầu hết cần tên và mật khẩu, nên câu hỏi thứ hai là engine xử lý tiêu đề Proxy-Authorization thế nào, nhất là với HTTPS. Phần sau đi vào chuyện này.

Nếu cần SOCKS5 trên JVM, bảng chỉ để lại OkHttp. CIO, Java và Apache đều không hỗ trợ SOCKS theo bảng. Với project server dùng CIO, muốn SOCKS thì phải đổi engine hoặc dùng cổng HTTP của nhà cung cấp.

Chọn engine cho bài toán proxy

Mình gợi ý chọn theo ba câu hỏi: có cần SOCKS không, có cần proxy có tài khoản với HTTPS không, và project chạy trên nền nào. Với server JVM cần proxy HTTP có tài khoản, OkHttp và Apache có cơ chế xác thực proxy riêng trong client gốc, dễ cấu hình hơn. CIO nhẹ và thuần Kotlin, nhưng cần kiểm kỹ cách xác thực.

Với Android, engine Android hoặc OkHttp đều hỗ trợ HTTP và SOCKS. Với iOS dùng Darwin, nhớ giới hạn HTTPS. Với Kotlin/JS chạy trong trình duyệt, proxy do trình duyệt quyết định, giống mọi mã JavaScript khác.

Cấu hình Ktor Client proxy cơ bản

Phụ thuộc cần khai báo

Tài liệu ghi rằng không cần phụ thuộc riêng cho proxy. Anh em chỉ cần ktor-client-core và một engine. Ví dụ với Gradle Kotlin DSL dùng CIO và OkHttp:

dependencies {
    implementation("io.ktor:ktor-client-core:3.6.0")
    implementation("io.ktor:ktor-client-cio:3.6.0")
    implementation("io.ktor:ktor-client-okhttp:3.6.0")
}

Khóa đúng một bản Ktor cho mọi module ktor-client. Trộn bản lớn khác nhau giữa core và engine là nguồn lỗi khó hiểu. Với nhiều module, dùng version catalog của Gradle để giữ một chỗ khai báo phiên bản.

ProxyBuilder.http và ProxyBuilder.socks

Proxy được đặt trong khối engine của HttpClient. Tài liệu đưa ví dụ ProxyBuilder.http với URL proxy và ProxyBuilder.socks với tên máy và cổng.

import io.ktor.client.*
import io.ktor.client.engine.*
import io.ktor.client.engine.cio.*
 
val client = HttpClient(CIO) {
    engine {
        proxy = ProxyBuilder.http("http://203.0.113.10:8080/")
    }
}

Với SOCKS trên engine hỗ trợ, như OkHttp:

import io.ktor.client.engine.okhttp.*
 
val socksClient = HttpClient(OkHttp) {
    engine {
        proxy = ProxyBuilder.socks(host = "203.0.113.10", port = 1080)
    }
}

Trên JVM, tài liệu cho biết ProxyConfig tương ứng với lớp java.net.Proxy. Vì vậy anh em cũng có thể gán thẳng Proxy(Proxy.Type.HTTP, InetSocketAddress(host, port)) nếu thích kiểu viết của Java.

Đọc cấu hình từ biến môi trường

Không ghi địa chỉ và tài khoản proxy cứng trong mã. Đọc từ biến môi trường hoặc tệp cấu hình của ứng dụng rồi dựng ProxyConfig khi tạo client.

fun proxyFromEnv(): ProxyConfig? {
    val host = System.getenv("PROXY_HOST") ?: return null
    val port = System.getenv("PROXY_PORT")?.toIntOrNull() ?: return null
    return when (System.getenv("PROXY_TYPE") ?: "http") {
        "socks" -> ProxyBuilder.socks(host, port)
        else -> ProxyBuilder.http("http://$host:$port/")
    }
}

Hàm trả null khi thiếu biến, để client chạy không proxy trong môi trường phát triển. Ở môi trường thật, nên ném lỗi khi thiếu biến thay vì lặng lẽ đi thẳng. Đi thẳng nhầm là lỗi khó phát hiện nhất vì mọi request vẫn thành công.

Xác thực Ktor Client proxy có tài khoản

Cách tài liệu Ktor hướng dẫn

Tài liệu Ktor nói rõ xác thực proxy phụ thuộc engine và phải xử lý thủ công. Ví dụ trong tài liệu gắn tiêu đề Proxy-Authorization vào mọi request bằng defaultRequest, với giá trị Basic cộng chuỗi base64 của tên và mật khẩu.

import io.ktor.client.plugins.*
import io.ktor.http.*
import java.util.Base64
 
val client = HttpClient(CIO) {
    engine {
        proxy = ProxyBuilder.http("http://${System.getenv("PROXY_HOST")}:${System.getenv("PROXY_PORT")}/")
    }
    defaultRequest {
        val raw = "${System.getenv("PROXY_USER")}:${System.getenv("PROXY_PASS")}"
        val credentials = Base64.getEncoder().encodeToString(raw.toByteArray())
        header(HttpHeaders.ProxyAuthorization, "Basic $credentials")
    }
}

Cách này đơn giản và chạy được trên nhiều engine với URL http. Nhưng nó có một giới hạn quan trọng cần hiểu trước khi dùng cho API HTTPS.

Giới hạn với URL https

Tiêu đề không nằm trong CONNECT

Tiêu đề không nằm trong CONNECT

Với URL http, client gửi request dạng địa chỉ đầy đủ tới proxy, tiêu đề Proxy-Authorization nằm ngay trong request đó và proxy đọc được. Với URL https, client phải mở đường hầm bằng lệnh CONNECT trước, rồi mới gửi request đã mã hóa bên trong. Tiêu đề gắn bằng defaultRequest thuộc về request bên trong, không tự động nằm trong lệnh CONNECT.

Nếu engine không chép tiêu đề này sang lệnh CONNECT, proxy sẽ trả 407 cho CONNECT và request HTTPS thất bại. Đây là suy luận từ cách giao thức hoạt động theo RFC 9110 về CONNECT, mình chưa chạy thử trên từng engine. Với proxy có tài khoản và API HTTPS, phải kiểm riêng ca HTTPS trên đúng engine trước khi tin cấu hình.

Dùng cơ chế xác thực của client gốc

Với OkHttp, client gốc có proxyAuthenticator, được gọi khi proxy trả 407, kể cả cho lệnh CONNECT. Ktor cho phép cấu hình OkHttpClient bên dưới trong khối engine bằng config. Đoạn dưới là ví dụ triển khai dựa trên API của OkHttp, không lấy từ tài liệu Ktor.

import okhttp3.Credentials
 
val okClient = HttpClient(OkHttp) {
    engine {
        proxy = ProxyBuilder.http("http://${System.getenv("PROXY_HOST")}:${System.getenv("PROXY_PORT")}/")
        config {
            proxyAuthenticator { _, response ->
                if (response.request.header("Proxy-Authorization") != null) return@proxyAuthenticator null
                response.request.newBuilder()
                    .header("Proxy-Authorization", Credentials.basic(System.getenv("PROXY_USER"), System.getenv("PROXY_PASS")))
                    .build()
            }
        }
    }
}

Dòng kiểm tiêu đề đã có giúp tránh vòng lặp vô hạn khi tài khoản sai: lần thứ hai bị 407, authenticator trả null và OkHttp dừng. OkHttp dùng cơ chế authenticator tương tự cho xác thực website, chỉ khác tên phương thức.

Với engine Java, client HTTP tích hợp của JDK dùng Authenticator và chịu thuộc tính jdk.http.auth.tunneling.disabledSchemes. Bài Java proxy giải thích cách bật lại xác thực Basic cho đường hầm. Với engine Apache, client gốc có credentials provider riêng cho proxy.

Ktor Client proxy với SOCKS

SOCKS trên OkHttp và Android

Theo bảng, trên JVM chỉ OkHttp hỗ trợ SOCKS. Cấu hình bằng ProxyBuilder.socks như ví dụ ở trên. Với SOCKS có tài khoản, tài liệu Ktor trỏ tới hai system properties của JVM là java.net.socks.username và java.net.socks.password.

System.setProperty("java.net.socks.username", System.getenv("SOCKS_USER"))
System.setProperty("java.net.socks.password", System.getenv("SOCKS_PASS"))

Hai thuộc tính này áp dụng cho cả JVM, không riêng một client. Nếu ứng dụng có nhiều client SOCKS với tài khoản khác nhau, cách này không đủ, cần Authenticator riêng hoặc tách tiến trình.

Phân giải tên miền khi dùng SOCKS

Với SOCKS5, câu hỏi quan trọng là máy nào phân giải tên miền. Nếu client tự phân giải rồi gửi IP cho proxy, nhà mạng của máy chủ vẫn thấy truy vấn DNS. Nếu gửi nguyên tên miền, proxy phân giải và DNS không rò ra ngoài.

Với java.net.Proxy kiểu SOCKS, Java thường gửi tên miền cho proxy khi địa chỉ được tạo chưa phân giải, nhưng hành vi cụ thể phụ thuộc cách engine tạo socket. Mình chưa kiểm trên OkHttp qua Ktor. Bài DNS leak khi dùng proxy có cách kiểm rò rỉ DNS bằng công cụ bên ngoài.

Khi nào bỏ SOCKS

Nếu engine đang dùng là CIO và gói proxy có cả cổng HTTP, chọn cổng HTTP. Đổi engine chỉ để dùng SOCKS là chi phí lớn, kéo theo đổi hành vi timeout, pool kết nối và cách xử lý lỗi. Bài proxy HTTP và SOCKS5 giúp quyết định khi nào SOCKS5 thật sự cần thiết.

Timeout, thử lại và lỗi của Ktor Client proxy

Plugin HttpTimeout

Ktor có plugin HttpTimeout với ba thông số: requestTimeoutMillis, connectTimeoutMillis và socketTimeoutMillis. Khi đi qua proxy, connectTimeoutMillis đo việc kết nối tới proxy, không phải tới website. requestTimeoutMillis bao cả vòng đời request.

import io.ktor.client.plugins.*
 
val client = HttpClient(CIO) {
    engine { proxy = proxyFromEnv() }
    install(HttpTimeout) {
        connectTimeoutMillis = 5_000
        socketTimeoutMillis = 15_000
        requestTimeoutMillis = 30_000
    }
}

Đặt timeout rõ ràng giúp proxy treo không giữ coroutine mãi. Khi timeout xảy ra, Ktor ném ngoại lệ riêng cho từng loại, giúp biết chậm ở bước kết nối hay ở bước chờ dữ liệu.

Plugin HttpRequestRetry

Plugin HttpRequestRetry cho phép thử lại khi gặp lỗi máy chủ hoặc ngoại lệ mạng. Với proxy, mình chỉ bật thử lại cho lỗi mạng tạm thời và mã 5xx, giới hạn ba lần, khoảng nghỉ tăng dần.

install(HttpRequestRetry) {
    retryOnServerErrors(maxRetries = 3)
    retryOnException(maxRetries = 3, retryOnTimeout = true)
    exponentialDelay()
}

Cẩn thận với POST. Thử lại một request tạo đơn hàng hay gửi biểu mẫu qua proxy chập chờn có thể tạo bản ghi trùng. Với thao tác không an toàn khi gửi lại, tắt thử lại hoặc dùng khóa chống trùng phía máy chủ.

Phân biệt lỗi proxy và lỗi website

Khi request tới được website, Ktor trả HttpResponse với mã trạng thái, kể cả 403 hay 429. Nếu đã cài expectSuccess = true, Ktor ném ClientRequestException cho 4xx và ServerResponseException cho 5xx. Những lỗi này nghĩa là proxy đã làm xong việc của nó.

Lỗi proxy thật sự thường là ngoại lệ kết nối, timeout kết nối, hoặc phản hồi 407 khi request http được proxy từ chối. Với HTTPS, 407 cho CONNECT có thể hiện thành ngoại lệ I/O tùy engine. Ghi log cả chuỗi nguyên nhân của ngoại lệ để thấy thông điệp gốc.

Bảng: Phân biệt lỗi proxy và lỗi website

Hiện tượng

Thường do

Kiểm trước

Request vẫn ra IP máy chủ

Engine không hỗ trợ proxy, ví dụ Jetty hoặc JS

Bảng hỗ trợ theo engine

http chạy, https báo lỗi xác thực

Tiêu đề không nằm trong CONNECT

Dùng xác thực của client gốc

Ngoại lệ kết nối tới cổng proxy

Sai máy, cổng hoặc tường lửa

PROXY_HOST, PROXY_PORT

403, 429 từ website

IP bị hạn chế hoặc tần suất cao

Giảm tốc, đổi IP

SOCKS bị bỏ qua

Engine CIO, Java hoặc Apache

Đổi sang OkHttp hoặc dùng HTTP

Bảng này gom các tình huống từ tài liệu và từ cách giao thức hoạt động, chưa phải kết quả lab. Khi gặp lỗi 407 cụ thể, bài sửa lỗi 407 Proxy Authentication Required liệt kê nguyên nhân phía nhà cung cấp.

Với Ktor Client proxy, cấu hình đúng trên một engine không bảo đảm đúng trên engine khác. Đổi engine là phải chạy lại toàn bộ ca kiểm proxy.

Ktor Client proxy trong project đa nền tảng

Tách cấu hình theo nền

Trong project Kotlin Multiplatform, mỗi nền thường dùng engine khác: OkHttp hoặc Android cho Android, Darwin cho iOS, CIO hoặc OkHttp cho JVM server. Cách gọn là khai báo hàm tạo client kiểu expect trong mã chung, rồi viết actual cho từng nền với engine và proxy riêng.

Mã chung chỉ gọi client.get hay client.post, không biết gì về proxy. Nhờ vậy giới hạn của từng engine, như Darwin không hỗ trợ HTTPS qua proxy HTTP, không lan sang mã nghiệp vụ. Anh em chỉ cần ghi rõ nền nào hỗ trợ proxy nào trong tài liệu project.

Không ép proxy vào ứng dụng di động khi không cần

Với ứng dụng di động phát hành cho người dùng, việc đặt proxy cứng trong ứng dụng hiếm khi đúng. Mạng của người dùng đã có cài đặt riêng. Proxy trong Ktor phía di động thường chỉ dùng cho bản kiểm thử, cho công cụ nội bộ hoặc cho môi trường doanh nghiệp có chính sách rõ ràng.

Với server JVM thu thập dữ liệu hay gọi API đối tác, proxy trong Ktor có ý nghĩa thực tế hơn. Đây cũng là nơi cần kiểm kỹ xác thực, timeout và số kết nối đồng thời.

Giới hạn kết nối đồng thời

Gói proxy thường giới hạn số luồng cùng lúc. Engine CIO có cấu hình maxConnectionsCount và endpoint.maxConnectionsPerRoute. Với OkHttp, Dispatcher của OkHttp giới hạn số request đồng thời theo host. Đặt các giá trị này bằng hoặc thấp hơn hạn mức của gói proxy.

Khi vượt hạn mức, proxy có thể từ chối kết nối mới hoặc cắt kết nối đang chạy. Trong log, hiện tượng này trông giống mạng chập chờn. Kiểm số kết nối đồng thời trước khi nghĩ tới chuyện đổi proxy.

Chạy đối chứng Ktor Client proxy

Dựng proxy cục bộ có nhật ký

Cách chắc nhất để biết client đi đường nào là trỏ nó vào một proxy ghi nhật ký. Có thể dùng mitmproxy ở chế độ thường, Squid hoặc một proxy nhỏ tự viết. Yêu cầu là proxy ghi được phương thức, host đích và có hay không tiêu đề Proxy-Authorization.

Cấu hình proxy cục bộ đòi tài khoản. Chạy client lần lượt với từng engine dự định dùng. Mỗi lần ghi lại engine, URL, kết quả và dòng nhật ký tương ứng phía proxy.

Bộ ca kiểm tối thiểu

Danh sách dưới bao phủ các điểm dễ trượt nhất. Chạy đủ trên từng engine, đừng suy từ engine này sang engine khác.

  • GET http có tài khoản: proxy ghi request dạng địa chỉ đầy đủ, có Proxy-Authorization.
  • GET https có tài khoản: proxy ghi CONNECT. Kiểm CONNECT có mang Proxy-Authorization không.
  • Sai mật khẩu: client báo lỗi rõ ràng, không treo, không thử lại vô hạn.
  • Proxy chết: ngoại lệ kết nối trong thời gian connectTimeoutMillis.
  • SOCKS trên OkHttp: proxy SOCKS ghi kết nối, kiểm kiểu địa chỉ là tên miền hay IP.
  • Kiểm IP ra: gọi dịch vụ trả IP, so với IP proxy mong đợi.

Ca GET https có tài khoản là ca quyết định. Nếu ca này lỗi trên CIO với defaultRequest, chuyển sang OkHttp với proxyAuthenticator hoặc dùng proxy xác thực theo IP.

MockEngine không kiểm được proxy

Ktor có MockEngine để viết test không cần mạng. MockEngine trả response giả ngay trong tiến trình, không mở kết nối nào. Vì vậy mọi test chạy bằng MockEngine đều xanh dù cấu hình proxy sai hay đúng. Đây là cái bẫy hay gặp: nhóm có hàng trăm test đạt nhưng chưa có test nào chạm tới proxy.

Cách tách hợp lý là hai tầng test. Tầng thứ nhất dùng MockEngine cho logic nghiệp vụ: đọc JSON, xử lý mã lỗi, ánh xạ dữ liệu. Tầng thứ hai là test tích hợp chạy engine thật qua proxy cục bộ có nhật ký, kiểm các ca ở danh sách trên. Tầng hai chạy ít hơn, có thể chỉ trong pipeline trước khi triển khai, nhưng không được bỏ.

Với test tích hợp, đặt địa chỉ proxy cục bộ qua biến môi trường của pipeline, không viết cứng trong mã test. Khi đổi sang proxy thật ở môi trường staging, chỉ cần thay biến. Nếu test tích hợp lỗi ở ca HTTPS có tài khoản, đó là tín hiệu cần xem lại cách xác thực của engine, không phải lỗi logic nghiệp vụ.

Một mẹo nhỏ là cho test tích hợp đọc lại nhật ký proxy sau khi chạy, đếm số dòng CONNECT và số dòng có tài khoản. So con số đó với số request test đã gửi. Nếu ít hơn, có request đã đi thẳng mà không ai biết.

Ghi kết quả thành bảng của nhóm

Sau khi chạy, lập bảng engine, bản Ktor, bản JDK và kết quả từng ca. Bảng này có giá trị hơn mọi bài hướng dẫn, kể cả bài này, vì nó phản ánh đúng môi trường của anh em. Mỗi lần nâng Ktor, chạy lại và cập nhật bảng.

Đưa Ktor Client proxy vào dự án thật

Một client cho mỗi tuyến mạng

Một client cho mỗi tuyến

Một client cho mỗi tuyến

HttpClient của Ktor nên tạo một lần và dùng lại, vì nó giữ pool kết nối. Nếu ứng dụng cần một tuyến qua proxy và một tuyến đi thẳng cho API nội bộ, tạo hai client riêng. Đừng tạo client mới cho mỗi request, vừa chậm vừa rò rỉ tài nguyên.

Khi tắt ứng dụng, gọi client.close() để đóng pool. Với proxy xoay đổi IP theo tên người dùng, mỗi phiên cần client riêng với tài khoản riêng. Đóng client cũ khi đổi phiên.

Chọn loại proxy

Ktor trên server thường dùng để gọi API và lấy dữ liệu. Với API yêu cầu IP cố định, proxy tĩnh phù hợp. Với lấy dữ liệu từ nhiều trang công khai, proxy xoay giúp chia tải. Với cả hai, proxy xác thực theo IP giúp tránh câu chuyện tiêu đề trong CONNECT ở trên.

ProxyVN có proxy dân cư tĩnh, datacenter và proxy xoay, hỗ trợ HTTP và SOCKS5, cấp tài khoản user và mật khẩu. Khi cần proxy để chạy bộ ca kiểm trên engine đã chọn, anh em có thể mua proxy tốc độ cao tại trang chủ ProxyVN rồi thay biến môi trường.

Giữ bí mật

Không in giá trị Proxy-Authorization ra log. Plugin Logging của Ktor có thể ghi tiêu đề request ở mức ALL hoặc HEADERS. Nếu bật Logging, dùng sanitizeHeader để che tiêu đề Authorization và Proxy-Authorization.

install(Logging) {
    level = LogLevel.HEADERS
    sanitizeHeader { header -> header == HttpHeaders.Authorization || header == HttpHeaders.ProxyAuthorization }
}

Trên CI, đưa tài khoản proxy vào mục secret. Sau khi kiểm thử xong, đổi mật khẩu tài khoản proxy dùng thử nếu đó là tài khoản thật.

Ktor Client proxy khi lấy dữ liệu từ website

Tiêu đề, cookie và User-Agent

Proxy chỉ đổi IP nguồn, không đổi những gì client tự gửi đi. Ktor mặc định gửi User-Agent riêng của engine hoặc của Ktor. Website nhận ra User-Agent của thư viện rất dễ, nên dù IP sạch, request vẫn có thể bị chặn hoặc nhận nội dung khác người dùng thật.

Plugin UserAgent và defaultRequest cho phép đặt User-Agent và các tiêu đề chung như Accept-Language. Plugin HttpCookies giữ cookie giữa các request trong cùng client. Khi dùng proxy xoay, nhớ rằng cookie phiên gắn với IP cũ có thể làm website nghi ngờ khi IP đổi giữa chừng.

Giữ phiên ổn định với proxy tĩnh

Với luồng cần đăng nhập rồi mới lấy dữ liệu, giữ một IP trong suốt phiên là cách an toàn hơn. Tạo một client cho mỗi phiên, gắn một proxy tĩnh hoặc một phiên của proxy xoay có thời gian giữ IP đủ dài. Khi phiên kết thúc, đóng client cùng cookie của nó.

Ngược lại, với các trang công khai không cần đăng nhập, mỗi lô request có thể dùng một IP khác để chia tải. Lúc đó cookie ít quan trọng, cái cần quản lý là tốc độ gửi để không vượt ngưỡng của website.

Giới hạn tốc độ ở tầng mã

Ktor không có bộ giới hạn tốc độ tích hợp cho client. Với coroutine, anh em có thể dùng Semaphore của kotlinx.coroutines để giới hạn số request đồng thời, kèm delay giữa các lô. Đặt số đồng thời bằng hoặc thấp hơn số luồng gói proxy cho phép.

Khi tỷ lệ 429 tăng, giảm tốc trước, đổi IP sau. Bài lỗi 429 khi dùng proxy có các cách đọc tiêu đề Retry-After và xếp lịch gửi lại.

Câu hỏi thường gặp về Ktor Client proxy

Engine nào nên chọn khi cần proxy có tài khoản trên server. OkHttp có proxyAuthenticator xử lý 407 cho cả CONNECT, nên là lựa chọn dễ kiểm nhất. CIO nhẹ hơn nhưng cần kiểm kỹ ca HTTPS có tài khoản.

Ktor có đọc biến môi trường HTTP_PROXY không. Tài liệu proxy của Ktor không nói Ktor tự đọc biến này. Một số engine có thể theo cài đặt của client gốc hoặc JVM, nhưng mình khuyên đọc biến trong mã và gán proxy rõ ràng.

Có cần phụ thuộc riêng cho proxy không. Không. Tài liệu ghi chỉ cần ktor-client-core và một engine.

Vì sao cấu hình proxy không có tác dụng trên Kotlin/JS. Engine JavaScript không hỗ trợ proxy theo bảng. Trong trình duyệt, proxy do trình duyệt quyết định.

SOCKS có tài khoản cấu hình ở đâu. Tài liệu Ktor trỏ tới hai system properties java.net.socks.username và java.net.socks.password trên JVM. Chúng áp cho cả JVM.

Darwin có dùng được proxy cho API HTTPS không. Theo ghi chú trong tài liệu, hiện chưa hỗ trợ HTTPS qua proxy HTTP với engine Darwin.

Nâng Ktor lên bản mới có cần kiểm lại proxy không. Có. Mỗi bản Ktor có thể đổi bản engine đi kèm, ví dụ bản OkHttp bên dưới. Hành vi xác thực và timeout có thể khác. Chạy lại bộ ca kiểm và cập nhật bảng kết quả của nhóm trước khi triển khai bản nâng cấp.

Proxy có làm chậm request nhiều không. Có thêm một chặng mạng, thường cộng vài chục tới vài trăm mili giây tùy vị trí proxy so với máy chủ và website. Đo bằng log thời gian của hai client, một qua proxy và một đi thẳng, để biết con số thật trong hệ thống của anh em.

Checklist Ktor Client proxy

Checklist Ktor Client proxy

Checklist Ktor Client proxy

Trước khi triển khai

Danh sách dưới đây gom các điểm đã nêu trong bài.

  • Biết engine đang dùng và đối chiếu bảng hỗ trợ HTTP, SOCKS.
  • Không dùng Jetty hay JS khi cần proxy trong mã.
  • Darwin không gửi HTTPS qua proxy HTTP theo tài liệu.
  • Kiểm ca https có tài khoản riêng, vì defaultRequest không bảo đảm tiêu đề nằm trong CONNECT.
  • OkHttp dùng proxyAuthenticator cho proxy có tài khoản.
  • Cài HttpTimeout với connect, socket và request timeout.
  • Thử lại không áp cho POST khi thao tác không an toàn.
  • Che Proxy-Authorization trong Logging.
  • Một client cho mỗi tuyến, đóng client khi tắt ứng dụng.

Giới hạn của bài

Mã chưa được biên dịch và chạy trên máy lab vì thiếu Kotlin, Gradle và JDK 11. Bảng hỗ trợ lấy từ tài liệu Ktor 3.6.0. Phần xác thực HTTPS là suy luận từ giao thức và API của client gốc, cần kiểm trên đúng engine. Chưa thử gateway thương mại, chưa thử iOS và Android thật.

Ktor Client proxy và những điều cần nhớ

Ktor Client proxy đặt trong khối engine và phụ thuộc engine: Jetty, JS không hỗ trợ, SOCKS chỉ có ở OkHttp, Android, Darwin, Curl. Kiểm riêng ca HTTPS có tài khoản, dùng xác thực của client gốc khi cần, luôn cài timeout. Cần proxy ổn định cho Ktor Client proxy, liên hệ Proxy.vn - Nhà cung cấp dịch vụ proxy chất lượng hàng đầu Việt Nam.

TIN TỨC LIÊN QUAN