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!
Scala sttp proxy: cấu hình BackendOptions và kiểm no-proxy

Scala sttp proxy: cấu hình BackendOptions và kiểm no-proxy

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

Scala sttp proxy là cách cho thư viện sttp client gửi request qua máy trung gian bằng cấu hình của backend. Khác với proxy toàn JVM, sttp cho phép mỗi backend một proxy và một danh sách bỏ qua riêng. ProxyVN đối chiếu tài liệu sttp client4, viết project mẫu với backend ghi rõ, request đồng bộ và cách đọc lỗi khi proxy hoặc website trả lời sai.

Scala sttp proxy nằm ở backend

Request mô tả, backend thực thi

Request mô tả, backend thực thi

Request mô tả, backend thực thi

sttp của SoftwareMill tách hai phần rõ ràng. Request chỉ là một mô tả bất biến: phương thức, URI, tiêu đề, thân, cách đọc response. Backend mới là thứ mở kết nối và gửi request đi. Cùng một mô tả request có thể gửi bằng backend đồng bộ, backend Future hay backend của thư viện hiệu ứng như cats-effect hay ZIO.

Vì proxy là chuyện của tầng mạng, nó thuộc về backend chứ không thuộc về request. Theo tài liệu proxy của sttp, anh em truyền BackendOptions.httpProxy khi tạo backend, rồi mọi request gửi qua backend đó đều đi proxy.

Muốn hai tuyến mạng, tạo hai backend. Đây là nguyên tắc thiết kế quan trọng nhất của bài và là chỗ sttp khác hẳn cách đặt http.proxyHost cho cả JVM.

Khác bài Java proxy chung ở đâu

Bài Java proxy nói về system properties áp cho toàn bộ JVM. sttp cũng đọc các thuộc tính đó theo mặc định, nhưng đồng thời cho phép đè bằng cấu hình riêng của từng backend. Điều này giúp một ứng dụng Scala có backend đi proxy cho website bên ngoài và backend đi thẳng cho dịch vụ nội bộ, không phụ thuộc cấu hình JVM.

Bài này không lặp lại phần JVM chung. Nó chỉ đi vào BackendOptions, nonProxyHosts, onlyProxyHosts, xác thực Basic khi đi đường hầm với backend dựa trên HttpClient, cùng cách xử lý response lỗi theo kiểu của sttp.

Phạm vi kiểm thử

Máy lab của ProxyVN hôm viết bài không có Scala, sbt, scala-cli hay JDK 11 trở lên. 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 sttp client4 bản latest đọc ngày 27/10/2026 và ghi rõ chỗ nào là suy luận.

Cuối bài có bộ ca kiểm với proxy cục bộ để anh em tự chạy. Hãy coi kết quả trên máy mình là chuẩn, đặc biệt ở các chỗ phụ thuộc bản JDK.

Chuẩn bị project cho Scala sttp proxy

Khai báo phụ thuộc

sttp client4 dùng gói com.softwaremill.sttp.client4 với module core. Với sbt, khai báo như sau, thay 4.0.x bằng bản cụ thể mà nhóm đã chọn và khóa lại.

// build.sbt
scalaVersion := "3.3.6"
libraryDependencies += "com.softwaremill.sttp.client4" %% "core" % "4.0.x"

Với scala-cli, có thể khai ngay trong tệp nguồn bằng chỉ thị using dep. Cách này tiện cho thử nghiệm nhanh, không cần dựng cả project sbt.

//> using scala 3.3.6
//> using dep com.softwaremill.sttp.client4::core:4.0.x

Ghi rõ bản Scala, bản sttp và bản JDK trong README. Ba con số này quyết định hành vi proxy, nhất là phần xác thực đường hầm.

Chọn backend và ghi tên rõ ràng

DefaultSyncBackend là backend đồng bộ mặc định trên JVM, dựa trên client HTTP tích hợp của Java. sttp còn có backend Future, backend cho cats-effect, ZIO và các backend dựa trên thư viện khác như OkHttp. Tài liệu proxy ghi phần xác thực proxy được hỗ trợ bởi các backend JVM.

Trong project, đặt tên backend theo tuyến mạng thay vì theo kiểu kỹ thuật. Ví dụ externalBackend và internalBackend dễ hiểu hơn backend1, backend2. Khi đọc log hay mã, người sau biết ngay request đi đường nào.

Biến môi trường cho thông tin proxy

Đọc PROXY_HOST, PROXY_PORT, PROXY_USER, PROXY_PASS từ biến môi trường. Không ghi trong mã hay tệp application.conf được commit. Nếu nhà cung cấp gửi dạng ip:port:user:pass, tách thành bốn biến. Bài định dạng proxy có bảng chuyển đổi.

Cấu hình Scala sttp proxy với BackendOptions

Proxy không cần tài khoản

Ví dụ tối thiểu trong tài liệu tạo DefaultSyncBackend với BackendOptions.httpProxy, rồi gửi basicRequest qua backend đó.

import sttp.client4.*
 
val backend = DefaultSyncBackend(
  options = BackendOptions.httpProxy(sys.env("PROXY_HOST"), sys.env("PROXY_PORT").toInt)
)
 
val response = basicRequest
  .get(uri"https://httpbin.org/ip")
  .send(backend)
 
println(response.code)
println(response.body)

Cách này hợp với proxy xác thực theo IP. Mọi request gửi bằng backend này đều qua proxy, trừ các host khớp danh sách bỏ qua ở phần sau.

Proxy có tài khoản

Tài liệu đưa phiên bản httpProxy nhận thêm tên và mật khẩu. Tên và mật khẩu là tham số riêng, không ghép vào chuỗi URL, nên không cần mã hóa phần trăm cho ký tự @ hay #.

import sttp.client4.*
 
val externalBackend = DefaultSyncBackend(
  options = BackendOptions.httpProxy(
    sys.env("PROXY_HOST"),
    sys.env("PROXY_PORT").toInt,
    sys.env("PROXY_USER"),
    sys.env("PROXY_PASS")
  )
)

Với URL http, như vậy là đủ để proxy nhận tài khoản. Với URL https qua backend dựa trên HttpClient, còn một bước nữa.

Mở lại Basic cho đường hầm HTTPS

Tài liệu sttp nói rõ: với backend dựa trên HttpClient, muốn dùng Basic cho đường hầm proxy, phải bỏ Basic khỏi thuộc tính jdk.http.auth.tunneling.disabledSchemes. Cách nhanh là đặt thuộc tính đó thành chuỗi rỗng.

System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "")

Đặt dòng này trước khi tạo backend, tốt nhất ở dòng đầu của main hoặc qua cờ -D khi khởi chạy JVM. Tài liệu sttp cảnh báo cách này có thể làm lộ tài khoản nếu bị chặn bắt, vì Basic chỉ là base64. Nó dẫn tới ghi chú phát hành Java 8u111, bản đã đổi mặc định này.

Triệu chứng điển hình khi quên bước này: URL http chạy được, URL https báo lỗi xác thực proxy dù tài khoản đúng. Gặp đúng triệu chứng đó, kiểm thuộc tính này trước tiên.

Kiểm no-proxy trong Scala sttp proxy bằng nonProxyHosts

nonProxyHosts thắng onlyProxyHosts

nonProxyHosts thắng onlyProxyHosts

Hai danh sách và quy tắc ưu tiên

BackendOptions có hai danh sách: nonProxyHosts là các host không đi proxy, onlyProxyHosts là các host duy nhất được đi proxy. Tài liệu ghi quy tắc như sau: chỉ có nonProxyHosts thì host khớp sẽ bỏ qua proxy; chỉ có onlyProxyHosts thì chỉ host khớp mới đi proxy; có cả hai thì nonProxyHosts thắng. Mặc định cả hai đều rỗng.

Quy tắc ưu tiên này quan trọng khi hai danh sách chồng nhau. Ví dụ onlyProxyHosts có *.example.com nhưng nonProxyHosts có api.example.com, thì api.example.com sẽ đi thẳng.

Ký tự đại diện chỉ ở đầu hoặc cuối

Tài liệu cho phép ký tự * chỉ làm tiền tố hoặc hậu tố. Ví dụ trong tài liệu là danh sách localhost, *.local và 127.*. Viết api.*.com sẽ không khớp như mong muốn vì ký tự đại diện nằm giữa.

import sttp.client4.*
 
val opts = BackendOptions
  .httpProxy(sys.env("PROXY_HOST"), sys.env("PROXY_PORT").toInt, sys.env("PROXY_USER"), sys.env("PROXY_PASS"))
 
val externalBackend = DefaultSyncBackend(
  options = opts.copy(proxy = opts.proxy.map(_.copy(nonProxyHosts = List("localhost", "127.*", "*.internal"))))
)

Cách sửa danh sách qua copy như trên dựa trên việc BackendOptions và cấu hình proxy là case class. Tên trường cụ thể anh em đối chiếu với mã nguồn của đúng bản sttp, vì mình chưa biên dịch đoạn này.

Ví dụ thực tế: website ngoài và API nội bộ

Giả sử ứng dụng lấy giá từ website đối tác và ghi vào API kho hàng nội bộ inventory.internal. Có hai cách. Cách thứ nhất là một backend có proxy với nonProxyHosts chứa *.internal. Cách thứ hai là hai backend riêng, một có proxy, một không.

Mình nghiêng về cách thứ hai cho dự án lớn. Hai backend tách bạch giúp đọc mã dễ hơn và tránh lỗi khi ai đó sửa danh sách bỏ qua. Cách thứ nhất hợp với script nhỏ, nơi một backend là đủ gọn. Bài no_proxy là gì giải thích thêm về quy ước bỏ qua proxy ở các công cụ khác.

Scala sttp proxy và system properties của JVM

Thứ tự sttp đọc thuộc tính mặc định

Khi không truyền proxy trong BackendOptions, tài liệu ghi sttp kiểm các system properties theo thứ tự và lấy cặp đầu tiên có giá trị. Thứ nhất là socksProxyHost và socksProxyPort với cổng mặc định 1080. Thứ hai là http.proxyHost và http.proxyPort, mặc định 80. Thứ ba là https.proxyHost và https.proxyPort, mặc định 443.

Thứ tự này có hệ quả bất ngờ. Nếu máy chủ có đặt socksProxyHost cho một mục đích khác, sttp sẽ dùng SOCKS cho mọi request dù anh em nghĩ đang dùng proxy HTTP. Kiểm các thuộc tính JVM đang có trước khi kết luận cấu hình sai.

SOCKS chỉ qua thuộc tính hệ thống

Trên trang proxy, SOCKS chỉ xuất hiện dưới dạng system property, không có phương thức tạo SOCKS riêng trong BackendOptions được mô tả. Nếu cần SOCKS5, cách theo tài liệu là đặt socksProxyHost, socksProxyPort trước khi tạo backend.

Lưu ý rằng client HTTP tích hợp của Java mà DefaultSyncBackend dùng có giới hạn với SOCKS. Mình chưa kiểm thực tế với sttp. Nếu gói proxy có cổng HTTP, chọn cổng HTTP cho sttp sẽ ít rủi ro hơn. Bài proxy HTTP và SOCKS5 giúp quyết định khi nào SOCKS5 thật sự cần.

Đè thuộc tính hệ thống bằng BackendOptions

Khi đã truyền BackendOptions.httpProxy, backend dùng cấu hình đó thay vì đọc system properties. Đây là cách tách một backend khỏi cấu hình chung của JVM. Ngược lại, backend tạo không có proxy trong options sẽ đọc system properties, nên có thể vô tình đi proxy nếu JVM đã đặt http.proxyHost.

Với backend nội bộ bắt buộc đi thẳng, mình khuyên kiểm trong test rằng nhật ký proxy không có dòng nào cho host nội bộ. Đừng dựa vào giả định rằng không truyền proxy nghĩa là đi thẳng.

Request đồng bộ qua Scala sttp proxy và xử lý lỗi

basicRequest và kiểu thân response

basicRequest là điểm bắt đầu cho request trong sttp client4. Với basicRequest, thân response mặc định được đọc thành chuỗi và bọc theo kết quả thành công hay thất bại của mã trạng thái. Theo tài liệu response của sttp, response có trường code và các phương thức như isSuccess, isServerError.

import sttp.client4.*
 
val r = basicRequest
  .get(uri"https://api.example.com/items?page=1")
  .header("Accept", "application/json")
  .send(externalBackend)
 
r.body match {
  case Right(json) => println(s"OK ${r.code}: ${json.take(200)}")
  case Left(err)   => println(s"Website tra ${r.code}: ${err.take(200)}")
}

Mã 4xx và 5xx không phải ngoại lệ. Tài liệu nói rõ: request hoàn tất nhưng mã không phải 2xx vẫn được coi là thành công ở tầng client. Nghĩa là proxy đã làm xong việc, website mới là bên trả lỗi.

Lỗi kết nối là ngoại lệ

Mã lỗi là website, ngoại lệ là proxy

Mã lỗi là website, ngoại lệ là proxy

Tài liệu ghi khi client hoặc kết nối lỗi, backend đồng bộ ném ngoại lệ, còn backend hiệu ứng trả về hiệu ứng thất bại. Proxy không mở cổng, đường hầm bị từ chối, timeout kết nối tới proxy đều rơi vào nhóm này.

import scala.util.{Try, Failure, Success}
 
Try(basicRequest.get(uri"https://api.example.com/items").send(externalBackend)) match {
  case Success(resp) => println(resp.code)
  case Failure(e) =>
    var t: Throwable = e
    while (t != null) {
      println(s"${t.getClass.getName}: ${t.getMessage}")
      t = t.getCause
    }
}

In cả chuỗi nguyên nhân giúp thấy thông điệp gốc từ client của Java, ví dụ lỗi kết nối bị từ chối tới đúng địa chỉ proxy. sttp chuẩn hóa lỗi kết nối thành ngoại lệ riêng của nó, nên kiểm cả tên lớp ngoài cùng và nguyên nhân bên trong.

Phân biệt nhanh bằng bảng

Bảng dưới gom các tình huống thường gặp với Scala sttp proxy theo tài liệu và cách giao thức hoạt động, chưa phải kết quả lab.

Bảng: Phân biệt nhanh bằng bảng

Hiện tượng

Ý nghĩa

Kiểm trước

Response có code 403 hoặc 429

Website từ chối

IP, tần suất, tiêu đề

Ngoại lệ kết nối tới địa chỉ proxy

Proxy không mở cổng

Máy, cổng, tường lửa

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

Basic bị tắt cho đường hầm

jdk.http.auth.tunneling.disabledSchemes

Host nội bộ bị đẩy ra proxy

Thiếu nonProxyHosts hoặc JVM đã đặt proxy

Danh sách bỏ qua, system properties

Request đi SOCKS bất ngờ

socksProxyHost đang có giá trị

Thuộc tính JVM

Khi gặp lỗi 407 cụ thể từ proxy, bài sửa lỗi 407 Proxy Authentication Required có danh sách nguyên nhân phía nhà cung cấp.

Với Scala sttp proxy, response có mã lỗi là website trả lời. Ngoại lệ mới là dấu hiệu proxy hoặc mạng gặp sự cố.

Timeout khi đi qua Scala sttp proxy

Hai loại timeout của sttp

Tài liệu timeout của sttp ghi hai mức. connectionTimeout đặt trong BackendOptions, áp cho cả backend, mặc định 30 giây. readTimeout đặt trên từng request, mặc định 1 phút, có thể tắt bằng Duration.Inf.

Khi đi qua proxy, connectionTimeout đo việc kết nối tới proxy. Mặc định 30 giây là khá dài cho proxy, một proxy chết sẽ làm mỗi request treo nửa phút trước khi báo lỗi. Mình đặt khoảng 5 giây cho tuyến proxy.

import scala.concurrent.duration.*
import sttp.client4.*
 
val opts = BackendOptions
  .httpProxy(sys.env("PROXY_HOST"), sys.env("PROXY_PORT").toInt, sys.env("PROXY_USER"), sys.env("PROXY_PASS"))
  .connectionTimeout(5.seconds)
 
val externalBackend = DefaultSyncBackend(options = opts)
 
val r = basicRequest
  .get(uri"https://api.example.com/slow-report")
  .readTimeout(20.seconds)
  .send(externalBackend)

Không tắt readTimeout cho tuyến proxy

Duration.Inf hữu ích cho tải tệp lớn hay luồng dữ liệu dài. Với tuyến proxy, tắt readTimeout nghĩa là một proxy treo giữa chừng sẽ giữ luồng mãi. Nếu cần tải tệp lớn qua proxy, đặt readTimeout dài nhưng hữu hạn, đủ cho tốc độ thấp nhất chấp nhận được.

readTimeout được tính trên dữ liệu nhận về, nên với API trả chậm vì phải tạo báo cáo, cần đặt đủ dài cho riêng request đó. Đó là lý do sttp cho đặt readTimeout ở từng request thay vì chỉ ở backend.

Thử lại có kiểm soát

sttp không tự thử lại request theo mặc định trong backend đồng bộ. Với lỗi mạng tạm thời qua proxy, anh em tự viết vòng thử lại cho GET, giới hạn số lần và có khoảng nghỉ tăng dần. Với POST tạo dữ liệu, không thử lại hoặc dùng khóa chống trùng phía máy chủ.

Khi website trả 429 liên tục, thử lại nhanh chỉ làm tệ hơn. Đọc tiêu đề Retry-After nếu có và giãn nhịp gửi. Bài lỗi 429 khi dùng proxy có cách xếp lịch gửi lại.

Scala sttp proxy với backend bất đồng bộ

Cùng BackendOptions, khác kiểu kết quả

Điểm mạnh của sttp là cùng mô tả request gửi được qua nhiều backend. BackendOptions cũng dùng chung: backend Future dựa trên HttpClient nhận cùng tham số options như DefaultSyncBackend. Khác biệt nằm ở kiểu kết quả: backend đồng bộ trả response ngay hoặc ném ngoại lệ, backend Future trả Future có thể thất bại.

Với ứng dụng dùng Future, lỗi proxy không còn là ngoại lệ ném ra ở chỗ gọi send. Nó nằm trong Future thất bại, cần xử lý bằng recover hoặc onComplete. Nếu quên, lỗi proxy có thể bị nuốt mất và request coi như chưa từng được gửi.

cats-effect và ZIO

Với cats-effect hay ZIO, backend thường được tạo dưới dạng Resource hoặc ZLayer. Cấu hình proxy vẫn qua BackendOptions khi tạo backend. Ưu điểm của cách này là backend tự đóng khi Resource kết thúc, pool kết nối tới proxy được giải phóng gọn.

Lỗi kết nối tới proxy trở thành hiệu ứng thất bại. Kết hợp với các toán tử thử lại của thư viện hiệu ứng, anh em có thể thử lại lỗi mạng một cách có kiểm soát, giới hạn số lần và khoảng nghỉ. Nhớ chỉ thử lại thao tác an toàn khi gửi lại, như GET hoặc PUT có tính lũy đẳng.

Mình chưa chạy thử backend cats-effect hay ZIO qua proxy. Phần này dựa trên mô hình chung của sttp: options đặt ở backend, request không biết gì về proxy. Khi dùng backend dựa trên thư viện khác HttpClient, hỗ trợ xác thực proxy có thể khác, cần kiểm lại ca https có tài khoản.

Giới hạn số request đồng thời

Backend bất đồng bộ cho phép gửi rất nhiều request cùng lúc. Gói proxy thường giới hạn số luồng, vượt ngưỡng thì proxy từ chối hoặc cắt kết nối. Với Future, dùng một bể luồng giới hạn hoặc chia lô. Với cats-effect, parTraverseN giới hạn số tác vụ song song. Với ZIO, foreachPar kèm withParallelism làm việc tương tự.

Đặt mức song song bằng hoặc thấp hơn hạn mức của gói proxy. Khi lỗi kết nối tăng đột ngột lúc chạy song song, giảm mức song song trước khi nghĩ tới chuyện proxy hỏng. Hiện tượng này rất hay bị nhầm với mạng chập chờn.

Scala sttp proxy khi lấy dữ liệu nhiều trang

Tiêu đề và User-Agent

Proxy chỉ đổi IP nguồn. Tiêu đề do sttp gửi, như User-Agent mặc định của thư viện, vẫn đi nguyên tới website. Website có thể nhận ra thư viện qua User-Agent và trả nội dung khác hoặc chặn. Đặt User-Agent và Accept-Language phù hợp bằng header trên request, hoặc tạo một request mẫu có sẵn tiêu đề rồi dùng lại.

Với website yêu cầu cookie phiên, sttp không tự giữ cookie giữa các request theo cách của trình duyệt. Anh em đọc cookie từ response rồi gắn vào request sau. Khi dùng proxy xoay, nhớ rằng cookie gắn với IP cũ có thể làm website nghi ngờ khi IP đổi giữa phiên.

Giữ IP ổn định cho luồng cần đăng nhập

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

Với trang công khai không cần đăng nhập, mỗi lô request có thể dùng backend gắn IP khác để chia tải. Lúc đó điều cần quản lý là tốc độ gửi, không phải cookie.

Chạy đối chứng Scala sttp proxy

Proxy cục bộ có nhật ký

Cách chắc nhất để kiểm cấu hình là cho backend đi qua một proxy ghi nhật ký. Dùng mitmproxy, Squid hoặc một proxy nhỏ tự viết, miễn ghi được phương thức, host đích và có tiêu đề Proxy-Authorization hay không.

Cấu hình proxy cục bộ đòi tài khoản. Tạo externalBackend trỏ vào nó và internalBackend không proxy. Chạy bộ ca dưới đây bằng một đối tượng main riêng hoặc test tích hợp.

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

  • GET http qua externalBackend: nhật ký proxy có request, có tài khoản.
  • GET https qua externalBackend: nhật ký có CONNECT. Nếu lỗi xác thực, kiểm thuộc tính disabledSchemes.
  • GET host trong nonProxyHosts: nhật ký không có dòng mới.
  • GET qua internalBackend: nhật ký không có dòng mới, kể cả khi JVM có http.proxyHost.
  • Sai mật khẩu: ngoại lệ hoặc lỗi rõ ràng, không treo.
  • Proxy chết: ngoại lệ trong khoảng connectionTimeout.
  • Kiểm IP ra: gọi dịch vụ trả IP, so với IP proxy mong đợi.

Ca thứ tư hay bị bỏ qua nhưng lại hay gây sự cố. Một ngày nào đó ai đó thêm -Dhttp.proxyHost vào lệnh chạy JVM, và backend nội bộ bắt đầu đi proxy. Có ca này trong pipeline thì lỗi lộ ra ngay.

Kiểm IP ra bằng một request nhỏ

Ca kiểm IP là cách nhanh nhất để biết externalBackend có thật sự đi proxy. Gọi một dịch vụ trả IP công khai, đọc chuỗi IP rồi so với IP mà gói proxy cam kết, hoặc ít nhất so với IP của máy chủ. Nếu trùng IP máy chủ, request đang đi thẳng.

val ipResp = basicRequest.get(uri"https://api.ipify.org").send(externalBackend)
val ip = ipResp.body.getOrElse("")
require(ip.nonEmpty && ip != sys.env("SERVER_PUBLIC_IP"), s"Request dang di thang, IP ra: $ip")

Đặt ca này ở bước đầu của pipeline triển khai và ở lúc khởi động dịch vụ. Khi ai đó đổi cấu hình, nâng sttp hay nâng JDK, ca này dừng mọi thứ trước khi request thật đi ra bằng IP sai. Mình cũng ghi IP ra vào log khởi động để đối chiếu khi có sự cố sau này.

Với proxy xoay, IP ra mỗi lần có thể khác nhau. Khi đó ca kiểm chỉ cần bảo đảm IP ra khác IP máy chủ, không cần khớp một IP cụ thể.

Ghi kết quả

Ghi bản Scala, sttp, JDK, tên backend và kết quả từng ca vào một bảng của nhóm. Mỗi lần nâng một trong ba bản, chạy lại. Bảng này phản ánh đúng môi trường của anh em và có giá trị hơn mọi hướng dẫn chung.

Đưa Scala sttp proxy vào dự án thật

Vòng đời backend

Backend giữ pool kết nối, nên tạo một lần và dùng lại. Khi ứng dụng tắt, gọi close trên backend. Với ứng dụng dùng cats-effect hay ZIO, các backend tương ứng thường được tạo dưới dạng Resource hoặc ZLayer để tự đóng.

Với proxy xoay đổi IP theo tên người dùng, mỗi phiên cần một backend với tài khoản riêng. Tạo backend mới cho phiên mới và đóng backend cũ. Đừng tạo backend mới cho từng request, vừa chậm vừa rò rỉ tài nguyên.

Chọn loại proxy

sttp thường dùng để gọi API và lấy dữ liệu trong dịch vụ backend. Với API đối tác 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. Proxy xác thực theo IP giúp tránh câu chuyện Basic trong đường hầm, nếu nhà cung cấp hỗ trợ.

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 HTTP cho externalBackend, anh em có thể mua proxy tại trang chủ ProxyVN rồi chạy lại bộ ca kiểm ở trên.

Giữ bí mật và log

Không in BackendOptions ra log vì nó chứa tài khoản. Khi ghi log request, chỉ ghi tên backend, host đích, mã trạng thái và thời gian. sttp có các backend bọc để ghi log, khi dùng nhớ che tiêu đề Authorization và Proxy-Authorization.

Trên CI, đưa tài khoản proxy vào mục secret. Sau khi kiểm xong với tài khoản thật, đổi mật khẩu nếu đã từng in ra màn hình hay lưu trong lịch sử lệnh.

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

Đặt proxy cho từng request được không. Proxy nằm trong BackendOptions của backend. Muốn tuyến khác, dùng backend khác, hoặc dùng nonProxyHosts và onlyProxyHosts để chọn theo host.

Mật khẩu có ký tự đặc biệt có cần mã hóa không. Không, vì tên và mật khẩu là tham số riêng của httpProxy.

Vì sao https báo lỗi xác thực proxy. Với backend dựa trên HttpClient, JDK tắt Basic cho đường hầm theo mặc định. Đặt jdk.http.auth.tunneling.disabledSchemes thành chuỗi rỗng như tài liệu sttp hướng dẫn.

sttp có tự đọc http.proxyHost không. Có, khi không truyền proxy trong options. Thứ tự là SOCKS trước, rồi http, rồi https.

Có SOCKS trong BackendOptions không. Trang proxy chỉ mô tả SOCKS qua system properties socksProxyHost và socksProxyPort.

Timeout mặc định bao nhiêu. connectionTimeout 30 giây, readTimeout 1 phút theo tài liệu. Với proxy, nên đặt connectionTimeout ngắn hơn.

Nâng JDK có ảnh hưởng tới proxy không. Có thể. Backend mặc định dựa trên client HTTP của JDK, nên mặc định về xác thực đường hầm và hành vi kết nối đi theo bản JDK. Sau mỗi lần nâng JDK, chạy lại ca https có tài khoản và ca backend nội bộ.

Proxy xoay dùng với sttp thế nào. sttp chỉ gửi tới địa chỉ proxy đã cấu hình. Với proxy xoay đổi IP theo tên người dùng, mỗi phiên một backend có tài khoản riêng. Với proxy đổi IP theo thời gian ở phía nhà cung cấp, một backend là đủ.

Checklist Scala sttp proxy

Checklist Scala sttp proxy

Checklist Scala sttp proxy

Trước khi triển khai

  • Ghi rõ backend và bản sttp, Scala, JDK.
  • Mỗi tuyến một backend, hoặc danh sách bỏ qua rõ ràng.
  • Đã mở Basic cho đường hầm nếu proxy có tài khoản và gọi https qua backend HttpClient.
  • Ký tự đại diện chỉ ở đầu hoặc cuối trong nonProxyHosts, onlyProxyHosts.
  • Kiểm system properties JVM, nhất là socksProxyHost.
  • connectionTimeout ngắn cho tuyến proxy, readTimeout hữu hạn.
  • Xử lý cả Left của body và ngoại lệ, vì hai loại lỗi đến từ hai nơi khác nhau.
  • Ca kiểm IP và ca backend nội bộ chạy trong pipeline.

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 Scala và JDK 11. Đoạn chỉnh nonProxyHosts bằng copy cần đối chiếu tên trường với mã nguồn đúng bản sttp. Chưa thử SOCKS, chưa thử backend cats-effect hay ZIO, chưa thử gateway thương mại.

Scala sttp proxy và những điều cần nhớ

Scala sttp proxy đặt trong BackendOptions của từng backend. Dùng hai backend cho hai tuyến, nonProxyHosts thắng onlyProxyHosts, mở Basic cho đường hầm khi gọi https có tài khoản, đặt connectionTimeout ngắn. Cần proxy ổn định cho Scala sttp 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