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!
Unirest Java proxy: cấu hình Unirest 4 và tách tuyến mạng

Unirest Java proxy: cấu hình Unirest 4 và tách tuyến mạng

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

Unirest Java proxy là cách cho thư viện Unirest gửi request HTTP qua máy trung gian. Unirest đặt proxy ở cấu hình, không đặt ở từng request, nên muốn hai tuyến mạng thì phải có hai instance. ProxyVN đối chiếu tài liệu Kong cho Unirest 4, viết project Maven mẫu với hai instance và các bước kiểm đường đi trước khi dùng thật.

Unirest Java proxy và cách Unirest quản lý cấu hình

Unirest 4 khác Unirest 3 ở tầng mạng

Unirest Java do Kong duy trì, ra đời như một trong loạt client HTTP cùng tên cho nhiều ngôn ngữ. Trang giới thiệu của Unirest Java ghi rằng tới bản 3, thư viện về cơ bản là lớp bọc quanh Apache HTTP. Bản 4 chuyển sang client HTTP tích hợp của Java và cần tối thiểu Java 11.

Thay đổi này ảnh hưởng thẳng tới proxy. Với Unirest 3, cấu hình proxy đi xuống Apache HttpClient 4. Với Unirest 4, cấu hình proxy được chuyển thành ProxySelector và Authenticator của gói java.net, đúng như trang Proxies mô tả. Những quy tắc của Java về xác thực proxy vì thế áp dụng cho Unirest 4.

Ví dụ Apache HttpClient hay java.net.http trên mạng không dùng thẳng cho Unirest được. Anh em phải cấu hình qua API của Unirest, rồi hiểu Unirest đang dịch nó xuống tầng nào.

Proxy nằm ở cấu hình, không ở request

Theo trang cấu hình Unirest, mọi thiết lập đi qua Unirest.config() và nên làm một lần hoặc rất ít lần. Khi Unirest đã kích hoạt, các tùy chọn ảnh hưởng tới việc tạo client không đổi được nữa nếu không shutdown hay reset rõ ràng.

Trong tài liệu hiện hành, mình không tìm thấy tùy chọn proxy cho từng request riêng lẻ. Vì vậy cách thiết kế đúng là mỗi tuyến mạng một instance. Instance A đi qua proxy cho website bên ngoài, instance B đi thẳng cho API nội bộ. Đó cũng là output bắt buộc của bài này.

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

Bài Java proxy đã nói về system properties http.proxyHost, ProxySelector và lỗi xác thực Basic khi đi đường hầm trong JDK. Bài C# HttpClient proxy xử lý chuyện tương tự bên .NET. Bài này không lặp lại các phần chung đó, chỉ đi vào API của Unirest: proxy toàn cục, instance riêng, ProxySelector theo host và cách đọc lỗi khi gọi JSON.

Chuẩn bị project Maven cho Unirest Java proxy

Khai báo phụ thuộc

Trang Installation của Unirest ghi Unirest 4 dùng BOM com.konghq:unirest-java-bom bản 4.5.1, kèm module lõi unirest-java-core. Lõi không kéo theo phụ thuộc nào, nên anh em phải chọn một module JSON: unirest-modules-gson hoặc unirest-modules-jackson.

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.konghq</groupId>
      <artifactId>unirest-java-bom</artifactId>
      <version>4.5.1</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
 
<dependencies>
  <dependency>
    <groupId>com.konghq</groupId>
    <artifactId>unirest-java-core</artifactId>
  </dependency>
  <dependency>
    <groupId>com.konghq</groupId>
    <artifactId>unirest-modules-gson</artifactId>
  </dependency>
</dependencies>

Nếu dự án còn ở Java 8, chỉ dùng được Unirest 3 với tọa độ com.konghq:unirest-java bản 3.14.1 theo cùng trang. Hai bản có tọa độ Maven khác nhau để tránh xung đột, đừng khai cả hai trong một project.

Khóa phiên bản Java và đặt biến môi trường

Trong pom.xml, đặt maven.compiler.release là 17 hoặc 21 tùy JDK của nhóm. Ghi rõ bản JDK trong README, vì hành vi xác thực proxy phụ thuộc vào bản JDK chứ không chỉ vào Unirest.

Thông tin proxy nên đọc từ biến môi trường: PROXY_HOST, PROXY_PORT, PROXY_USER, PROXY_PASS. Không ghi mật khẩu vào mã hay tệp cấu hình được commit. Nếu nhà cung cấp gửi chuỗi ip:port:user:pass, tách ra bốn biến này. Bài định dạng proxy có cách đổi giữa các kiểu viết.

Phạm vi kiểm thử của bài

Máy lab của ProxyVN hôm viết bài chỉ có JRE 8, không có JDK 11 trở lên và không có Maven. 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 API mô tả trong tài liệu chính thức của Unirest và JDK, kèm cách tự kiểm đường đi bằng proxy cục bộ ở phần sau.

Anh em nên chạy bộ kiểm ở mục đối chứng trước khi đưa mã vào dự án. Nếu kết quả khác mô tả, ưu tiên hành vi thực tế trên bản Unirest và JDK của mình.

Cấu hình Unirest Java proxy toàn cục

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

Trang Proxies của Unirest Java đưa cách đơn giản nhất: gọi proxy trên cấu hình với tên máy và cổng. Cấu hình này áp dụng cho instance chính, tức mọi lời gọi Unirest.get, Unirest.post tĩnh.

import kong.unirest.core.Unirest;
 
Unirest.config()
        .proxy(System.getenv("PROXY_HOST"), Integer.parseInt(System.getenv("PROXY_PORT")))
        .connectTimeout(5000)
        .requestTimeout(15000);

Cách này hợp với proxy cho phép theo IP, tức nhà cung cấp đã thêm IP máy chủ của anh em vào danh sách cho phép. Không có tài khoản nào được gửi đi.

Proxy có tài khoản

Khi proxy cần tên và mật khẩu, truyền thêm hai tham số. Trang Proxies ghi rằng khi có tài khoản, Unirest tạo một java.net.ProxySelector và một java.net.Authenticator.

Unirest.config().proxy(
        System.getenv("PROXY_HOST"),
        Integer.parseInt(System.getenv("PROXY_PORT")),
        System.getenv("PROXY_USER"),
        System.getenv("PROXY_PASS"));

Khác với các thư viện nhận proxy dạng URL, ở đây tên và mật khẩu là tham số riêng. Mật khẩu có @, # hay : không cần mã hóa phần trăm. Đây là một điểm tiện của API kiểu tham số so với kiểu chuỗi URL.

Xác thực Basic khi đi đường hầm HTTPS

Vì Unirest 4 dùng Authenticator của Java, quy tắc của JDK về xác thực proxy áp dụng nguyên vẹn. JDK mặc định tắt xác thực Basic cho đường hầm CONNECT qua thuộc tính jdk.http.auth.tunneling.disabledSchemes. Hệ quả hay gặp là URL http chạy được, còn URL https báo 407 dù tài khoản đúng.

Bài Java proxy đã giải thích kỹ thuộc tính này và cách bật lại bằng cờ JVM. Với Unirest, cờ đó đặt khi khởi chạy ứng dụng, trước khi Unirest tạo client. Đặt sau khi client đã tạo có thể không có tác dụng.

java -Djdk.http.auth.tunneling.disabledSchemes= -jar app.jar

Giá trị rỗng nghĩa là không tắt cơ chế nào. Chỉ bật lại Basic khi proxy thật sự cần, và hiểu rằng tài khoản sẽ đi dưới dạng mã hóa base64 tới proxy. Nếu nhà cung cấp hỗ trợ xác thực theo IP, đó là lựa chọn gọn hơn.

Tách hai tuyến Unirest Java proxy bằng instance

Mỗi tuyến mạng một instance

Mỗi tuyến mạng một instance

primaryInstance và spawnInstance

Trang cấu hình ghi Unirest giữ một instance chính, cấu hình được như ngữ cảnh tĩnh. Muốn một instance mới, độc lập với instance chính, gọi Unirest.spawnInstance(). Đây là chìa khóa để có hai tuyến mạng trong cùng ứng dụng.

import kong.unirest.core.Unirest;
import kong.unirest.core.UnirestInstance;
 
public final class Clients {
    public static final UnirestInstance EXTERNAL = Unirest.spawnInstance();
    public static final UnirestInstance INTERNAL = Unirest.spawnInstance();
 
    static {
        EXTERNAL.config()
                .proxy(env("PROXY_HOST"), Integer.parseInt(env("PROXY_PORT")), env("PROXY_USER"), env("PROXY_PASS"))
                .connectTimeout(5000)
                .requestTimeout(15000)
                .setDefaultHeader("Accept", "application/json");
 
        INTERNAL.config()
                .connectTimeout(2000)
                .requestTimeout(5000)
                .defaultBaseUrl("http://inventory.internal:8080");
    }
 
    private static String env(String key) {
        String v = System.getenv(key);
        if (v == null || v.isBlank()) throw new IllegalStateException("Thieu bien " + key);
        return v;
    }
}

EXTERNAL đi qua proxy cho website và API bên ngoài. INTERNAL không có proxy, dùng defaultBaseUrl cho API kho hàng nội bộ. Mỗi instance giữ client riêng, nên thay đổi cấu hình của một bên không ảnh hưởng bên kia.

Vì sao không dùng chung instance chính

Dùng instance chính với proxy toàn cục rồi mong API nội bộ đi thẳng là lỗi thiết kế hay gặp. Request tới inventory.internal sẽ bị đẩy ra proxy bên ngoài, proxy không phân giải được tên nội bộ và trả lỗi. Trong log, lỗi này trông như API nội bộ chết, trong khi thực ra API vẫn chạy.

Instance tách riêng cũng giúp kiểm thử. Trong test, anh em có thể thay EXTERNAL bằng instance trỏ về proxy cục bộ mà không đụng INTERNAL. Code nghiệp vụ chỉ nhận UnirestInstance qua tham số, không gọi Unirest tĩnh.

Đóng instance khi tắt ứng dụng

Instance tạo bằng spawnInstance giữ tài nguyên mạng. Khi ứng dụng tắt, gọi close hoặc shutdown trên từng instance để giải phóng. Với ứng dụng web, đặt việc này trong hook tắt của framework. Với tác vụ dòng lệnh, đặt trong khối finally của main.

Nếu cần đổi proxy giữa chừng, ví dụ đổi phiên của proxy xoay, cách an toàn là tạo instance mới với cấu hình mới rồi đóng instance cũ. Tài liệu đã cảnh báo cấu hình liên quan tới client không đổi được sau khi kích hoạt.

Unirest Java proxy theo từng host bằng ProxySelector

ProxySelector chọn proxy theo host

ProxySelector chọn proxy theo host

Khi nào cần ProxySelector

Có trường hợp anh em muốn một instance nhưng nhiều tuyến: vài tên miền đi proxy A, phần còn lại đi proxy B, tên nội bộ đi thẳng. Trang Proxies của Unirest có mục riêng cho tình huống này: tự viết ProxySelector và, nếu cần, Authenticator.

ProxySelector có phương thức select(URI) trả danh sách java.net.Proxy dựa theo host của request. Phương thức connectFailed được gọi khi kết nối tới proxy thất bại, trong ví dụ của Unirest để trống.

Mã mẫu

Đoạn dưới viết theo mẫu trong tài liệu, thay tên miền ví dụ bằng tên miền thật của dự án. Cách nạp ProxySelector vào cấu hình Unirest anh em đối chiếu với tài liệu của đúng bản đang dùng.

import java.io.IOException;
import java.net.*;
import java.util.List;
 
public class RouteSelector extends ProxySelector {
    private final Proxy shopProxy = new Proxy(Proxy.Type.HTTP,
            new InetSocketAddress(System.getenv("SHOP_PROXY_HOST"), 8080));
    private final Proxy defaultProxy = new Proxy(Proxy.Type.HTTP,
            new InetSocketAddress(System.getenv("PROXY_HOST"), Integer.parseInt(System.getenv("PROXY_PORT"))));
 
    @Override
    public List<Proxy> select(URI uri) {
        String host = uri.getHost();
        if (host.endsWith(".internal") || host.equals("localhost")) return List.of(Proxy.NO_PROXY);
        if (host.endsWith("shop.example.com")) return List.of(shopProxy);
        return List.of(defaultProxy);
    }
 
    @Override
    public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
        System.err.println("Khong ket noi duoc proxy " + sa + " cho " + uri.getHost());
    }
}

Khác với ví dụ trong tài liệu, mình ghi log trong connectFailed. Khi proxy chết, dòng log này cho biết proxy nào và host nào, đỡ phải đoán.

Authenticator theo host

Nếu hai proxy có hai tài khoản khác nhau, Authenticator phải trả tài khoản đúng theo proxy đang hỏi. Ví dụ của Unirest ghi đè requestPasswordAuthenticationInstance và trả PasswordAuthentication theo host, kèm lời nhắc đừng ghi mật khẩu cứng trong mã.

public class RouteAuth extends Authenticator {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        if (getRequestorType() != RequestorType.PROXY) return null;
        String host = getRequestingHost();
        if (host.equals(System.getenv("SHOP_PROXY_HOST"))) {
            return new PasswordAuthentication(System.getenv("SHOP_PROXY_USER"), System.getenv("SHOP_PROXY_PASS").toCharArray());
        }
        return new PasswordAuthentication(System.getenv("PROXY_USER"), System.getenv("PROXY_PASS").toCharArray());
    }
}

Kiểm getRequestorType là PROXY giúp Authenticator không vô tình gửi tài khoản proxy cho website đòi xác thực. Đây là lỗi bảo mật dễ bỏ qua khi chỉ chép ví dụ.

Gọi JSON qua Unirest Java proxy và đọc lỗi

Request JSON cơ bản

Sau khi có instance EXTERNAL, gọi API trả JSON theo kiểu chuỗi phương thức quen thuộc của Unirest. Module gson đã khai trong pom giúp Unirest đọc thân response thành đối tượng.

import kong.unirest.core.HttpResponse;
import kong.unirest.core.JsonNode;
 
HttpResponse<JsonNode> res = Clients.EXTERNAL.get("https://api.example.com/items")
        .queryString("page", 1)
        .asJson();
 
System.out.println(res.getStatus());
System.out.println(res.getBody().getObject().optJSONArray("items"));

Với POST, dùng body với đối tượng Java hoặc chuỗi JSON, kèm header Content-Type. Unirest dùng module JSON đã khai để chuyển đối tượng thành chuỗi.

record Order(String sku, int qty) {}
 
HttpResponse<String> created = Clients.EXTERNAL.post("https://api.example.com/orders")
        .header("Content-Type", "application/json")
        .body(new Order("A1", 2))
        .asString();

Lỗi website và lỗi proxy khác nhau

Unirest trả HttpResponse cho mọi response có mã trạng thái, kể cả 4xx và 5xx. Mã 403 hay 429 trong getStatus nghĩa là request đã qua proxy và tới được website. Khi đó vấn đề nằm ở IP, tần suất hoặc tiêu đề, không nằm ở cấu hình proxy.

Lỗi proxy thật sự xuất hiện dưới dạng ngoại lệ UnirestException với nguyên nhân bên dưới, ví dụ ConnectException khi proxy không mở cổng, hoặc lỗi I/O khi đường hầm bị từ chối. Với lỗi 407 trong đường hầm HTTPS, client của Java thường không trả response 407 cho mã ứng dụng mà ném ngoại lệ. Vì vậy cần ghi log cả chuỗi nguyên nhân.

try {
    HttpResponse<JsonNode> r = Clients.EXTERNAL.get("https://api.example.com/items").asJson();
    if (!r.isSuccess()) {
        System.err.println("Website tra " + r.getStatus());
    }
} catch (kong.unirest.core.UnirestException e) {
    Throwable t = e;
    while (t != null) {
        System.err.println(t.getClass().getName() + ": " + t.getMessage());
        t = t.getCause();
    }
}

Bộ xử lý lỗi toàn cục và ifFailure

Bảng tùy chọn của Unirest có errorHandler, một Consumer được gọi khi mã trạng thái trên 400 hoặc khi đọc thân lỗi. Đặt errorHandler trên EXTERNAL giúp ghi log tập trung mọi lỗi từ website bên ngoài mà không rải try khắp nơi.

Ở từng request, chuỗi ifSuccess và ifFailure trên HttpResponse cho phép xử lý gọn. Trong ifFailure, kiểm getParsingError để biết lỗi do website trả HTML thay vì JSON. Khi đi qua proxy, trang chặn của website hoặc trang lỗi của proxy thường là HTML, nên lỗi đọc JSON là dấu hiệu nên xem thân response thô.

Với Unirest Java proxy, mã 4xx và 5xx trong HttpResponse là website trả lời. Ngoại lệ UnirestException mới là dấu hiệu proxy hoặc mạng có vấn đề.

Timeout và thử lại với Unirest Java proxy

4xx là website, ngoại lệ là proxy

4xx là website, ngoại lệ là proxy

Hai loại timeout

Bảng cấu hình ghi connectTimeout mặc định 10000 ms và requestTimeout mặc định không giới hạn. Khi đi qua proxy, connectTimeout đo thời gian kết nối tới proxy, còn requestTimeout bao cả thời gian proxy chờ website trả lời.

Không đặt requestTimeout là rủi ro lớn nhất. Một proxy treo hoặc một website chậm có thể giữ luồng của anh em vô thời hạn. Mình đặt connectTimeout 5 giây và requestTimeout 15 giây cho EXTERNAL, ngắn hơn cho INTERNAL vì mạng nội bộ nhanh và ổn định hơn.

retryAfter chỉ dành cho 429 và 529

Unirest có retryAfter(boolean) và retryAfter(boolean, int). Theo bảng cấu hình, tùy chọn này thử lại request đồng bộ khi nhận 429 hoặc 529, dựa trên tiêu đề Retry-After. Mặc định tắt.

Đây không phải cơ chế thử lại chung cho lỗi mạng. Khi proxy từ chối kết nối, Unirest không tự thử lại theo tùy chọn này. Nếu cần thử lại lỗi mạng, anh em tự viết vòng lặp với số lần giới hạn và khoảng nghỉ tăng dần, chỉ áp cho GET hoặc thao tác an toàn khi gửi lại.

Khi website trả 429 liên tục qua proxy, thử lại không giải quyết gốc rễ. Bài lỗi 429 khi dùng proxy có các cách giảm tần suất và chia tải.

verifySsl và chứng chỉ

Bảng cấu hình có verifySsl, mặc định bật. Một số hướng dẫn trên mạng tắt nó để chữa lỗi chứng chỉ khi đi qua proxy. Đừng làm vậy với proxy HTTP thông thường, vì proxy kiểu CONNECT không chạm vào chứng chỉ của website.

Nếu thấy lỗi chứng chỉ chỉ khi đi qua proxy, có thể mạng công ty đang chặn và giải mã HTTPS. Khi đó cần nạp chứng chỉ gốc của công ty vào truststore của JVM, không phải tắt kiểm tra. Bài lỗi NET::ERR_CERT_AUTHORITY_INVALID giải thích hiện tượng này ở phía trình duyệt.

Chạy đối chứng Unirest Java proxy trước khi dùng thật

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

Cách chắc nhất để biết instance nào đi đường nào là cho nó đi qua một proxy mà anh em đọc được nhật ký. Có thể dùng mitmproxy, Squid hoặc một proxy nhỏ tự viết. Điều kiện duy nhất là proxy ghi lại mỗi kết nối kèm host đích.

Trỏ EXTERNAL vào proxy cục bộ, giữ INTERNAL không proxy. Gọi một URL bên ngoài bằng EXTERNAL và một URL nội bộ bằng INTERNAL. Nhật ký proxy chỉ được có dòng của URL bên ngoài. Nếu thấy cả URL nội bộ, cấu hình đang lẫn.

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

Mình đề xuất sáu ca, chạy bằng JUnit hoặc một lớp main riêng. Mỗi ca có kết quả mong đợi rõ ràng để không phải diễn giải.

Bảng: Bộ ca kiểm tối thiểu

Ca

Cách làm

Kết quả mong đợi

Tuyến ngoài

EXTERNAL gọi URL công khai

Nhật ký proxy có host đích

Tuyến nội bộ

INTERNAL gọi API nội bộ

Nhật ký proxy không có dòng mới

Sai mật khẩu

EXTERNAL với PROXY_PASS sai

Ngoại lệ, không có response 200

Proxy chết

Trỏ tới cổng không mở

Ngoại lệ ConnectException trong chuỗi nguyên nhân

HTTPS có tài khoản

Gọi URL https qua proxy Basic

Chạy được khi đã xử lý disabledSchemes

JSON hỏng

Gọi trang trả HTML

getParsingError khác rỗng

Ca HTTPS có tài khoản là ca dễ trượt nhất. Chạy nó với đúng JDK sẽ dùng trên máy chủ, vì mặc định của JDK có thể khác giữa các nhà phân phối.

Ca kiểm IP ra

Sau sáu ca trên, thêm một ca gọi dịch vụ trả IP công khai qua EXTERNAL. So IP nhận được với IP mà gói proxy cam kết. Nếu trùng IP máy chủ, request đang đi thẳng.

Đưa ca này vào bước đầu của pipeline triển khai. Khi ai đó đổi cấu hình hay nâng Unirest, ca này dừng pipeline trước khi request thật đi ra bằng IP sai.

Đưa Unirest Java proxy vào dự án thật

Tổ chức mã

Với dự án Spring hay Quarkus, tạo hai bean UnirestInstance có tên rõ ràng, tiêm vào service theo tên. Với ứng dụng thuần Java, một lớp Clients như ở trên là đủ. Mã nghiệp vụ không gọi Unirest tĩnh, để việc thay thế trong test dễ dàng.

Ghi log ở mức instance: tên instance, host đích, mã trạng thái, thời gian. Không ghi tài khoản proxy. Khi cần biết proxy nào được dùng, ghi PROXY_HOST, không ghi PROXY_PASS.

Chọn loại proxy

Unirest thường dùng để gọi API của đối tác hoặc lấy dữ liệu từ dịch vụ bên ngoài. Với API yêu cầu IP cố định trong danh sách cho phép, proxy tĩnh là lựa chọn hợp lý vì IP không đổi giữa các lần chạy. Với việc lấy dữ liệu từ nhiều trang công khai, proxy xoay giúp chia tải nhưng cần instance mới khi đổi phiê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 HTTP cho instance EXTERNAL, anh em có thể mua proxy uy tín tại trang chủ ProxyVN rồi chạy lại bộ sáu ca kiểm ở trên.

SOCKS5 với Unirest 4

Client HTTP tích hợp của Java không hỗ trợ proxy SOCKS cho HTTP theo cách client cũ HttpURLConnection làm. Vì Unirest 4 dựa trên client đó, mình không khuyên dùng SOCKS5 với Unirest 4 khi chưa tự kiểm. Nếu gói proxy có cả cổng HTTP, chọn cổng HTTP.

Nếu bắt buộc SOCKS5, cân nhắc Unirest 3 với Apache HttpClient hoặc một client khác có hỗ trợ rõ ràng, rồi chạy lại toàn bộ ca kiểm. Bài proxy HTTP và SOCKS5 giúp quyết định khi nào SOCKS5 thật sự cần.

Unirest Java proxy với Unirest 3 cho dự án Java 8

Khi nào còn phải dùng Unirest 3

Nhiều hệ thống doanh nghiệp vẫn chạy Java 8 vì phụ thuộc máy chủ ứng dụng cũ hoặc thư viện chưa nâng cấp. Với các hệ thống này, Unirest 4 không chạy được, lựa chọn còn lại là Unirest 3 với tọa độ com.konghq:unirest-java. Bản này bọc Apache HttpClient 4, nên cơ chế proxy đi theo Apache chứ không theo Authenticator của JDK.

Điểm khác thấy rõ nhất là tên gói. Unirest 3 dùng gói kong.unirest, còn Unirest 4 dùng kong.unirest.core. Mã chép từ hướng dẫn của bản này sang bản kia sẽ lỗi biên dịch ngay ở dòng import, đây là dấu hiệu đầu tiên để nhận ra hướng dẫn đang nói về bản nào.

Hành vi xác thực khác nhau

Vì Unirest 3 dùng Apache HttpClient, thuộc tính jdk.http.auth.tunneling.disabledSchemes của JDK không phải là yếu tố quyết định. Apache tự xử lý tiêu đề Proxy-Authorization theo cấu hình của nó. Điều đó có nghĩa là một cấu hình chạy trên Unirest 3 có thể báo lỗi xác thực khi nâng lên Unirest 4, dù mã ứng dụng không đổi dòng nào.

Khi lên kế hoạch nâng cấp từ 3 lên 4, mình khuyên chạy lại riêng ca HTTPS có tài khoản trước tiên. Đây là ca nhạy nhất với thay đổi tầng mạng. Trang Installation có nhắc tới hướng dẫn nâng cấp riêng, anh em nên đọc trước khi đổi tọa độ Maven.

Giữ cả hai bản trong giai đoạn chuyển tiếp

Vì hai bản có tọa độ Maven và tên gói khác nhau, về lý thuyết có thể đặt chúng trong hai module riêng của cùng một hệ thống. Tuy vậy, mình không khuyên trộn trong một module, vì người đọc mã sẽ khó biết request nào đi qua tầng mạng nào. Nếu buộc phải chuyển tiếp từ từ, tách theo module và ghi rõ trong README module nào dùng bản nào.

Ghi log Unirest Java proxy bằng interceptor

Interceptor toàn cục của instance

Bảng cấu hình có tùy chọn interceptor, nhận một đối tượng được gọi trước và sau mỗi request. Đây là chỗ hợp lý để ghi log mạng cho từng instance mà không chạm vào mã nghiệp vụ. Trang cấu hình gợi ý dùng interceptor cho log hoặc thêm thuộc tính chung.

Với proxy, mình ghi bốn thông tin: tên instance, host đích, mã trạng thái và thời gian chạy. Bốn thông tin này đủ để thấy instance EXTERNAL có chậm bất thường không, website nào trả 403 nhiều và giờ nào lỗi dồn dập. Mật khẩu proxy không bao giờ nằm trong log.

Đo thời gian theo tuyến

Khi so thời gian của EXTERNAL và INTERNAL, anh em sẽ thấy rõ chi phí thêm của chặng proxy. Thường chặng này cộng thêm vài chục tới vài trăm mili giây tùy vị trí proxy. Nếu con số tăng đột biến, có thể proxy đang quá tải hoặc tuyến từ máy chủ tới proxy có vấn đề.

Bảng cấu hình còn có instrumentWith để gắn số liệu trước và sau mỗi request. Với hệ thống đã có Prometheus hay OpenTelemetry, đây là cách đưa số liệu proxy vào bảng theo dõi chung thay vì đọc log thủ công.

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

Unirest có đặt proxy cho từng request được không. Trong tài liệu hiện hành, proxy nằm ở cấu hình. Muốn nhiều tuyến, tạo nhiều instance bằng spawnInstance hoặc dùng ProxySelector chọn theo host.

Mật khẩu proxy 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 phương thức proxy, không nằm trong chuỗi URL.

Vì sao http chạy mà https báo lỗi xác thực. Unirest 4 dùng Authenticator của JDK, và JDK mặc định tắt Basic cho đường hầm CONNECT. Xem thuộc tính jdk.http.auth.tunneling.disabledSchemes.

Dùng system properties http.proxyHost được không. Được. Trang Proxies hướng dẫn đặt http.proxyHost, http.proxyPort rồi gọi useSystemProperties(true). Cách này áp cho cả JVM, nên cân nhắc khi có API nội bộ.

Đổi proxy khi đang chạy thế nào. Tạo instance mới với proxy mới rồi đóng instance cũ. Tài liệu cảnh báo cấu hình tạo client không đổi được sau khi kích hoạt.

Unirest có hỗ trợ proxy xoay không. Unirest không phân biệt proxy tĩnh hay xoay, nó chỉ gửi request 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 cần một instance có tài khoản riêng. Với proxy xoay đổi IP theo thời gian ở phía nhà cung cấp, một instance là đủ, nhưng anh em cần biết rằng các request liên tiếp có thể ra IP khác nhau.

Có nên dùng Unirest để crawl số lượng lớn không. Unirest hợp cho gọi API và lấy dữ liệu vừa phải. Với crawl hàng trăm nghìn trang, anh em cần thêm hàng đợi, giới hạn tốc độ và lưu trạng thái, những thứ nằm ngoài phạm vi của một client HTTP. Khi đó Unirest chỉ là tầng gửi request, phần điều phối nên viết riêng.

Checklist Unirest Java proxy

Checklist Unirest Java proxy

Checklist Unirest Java proxy

Trước khi triển khai

Danh sách dưới đây gom các điểm đã nêu, dùng sau mỗi lần đổi cấu hình hay nâng phiên bản.

  • Đúng bản Unirest và JDK: Unirest 4 cần Java 11 trở lên, Unirest 3 cho Java 8.
  • Một module JSON đã khai, gson hoặc jackson.
  • Mỗi tuyến mạng một instance, không dùng proxy toàn cục cho cả API nội bộ.
  • Đã xử lý xác thực Basic cho đường hầm nếu proxy dùng tài khoản và gọi https.
  • Authenticator kiểm RequestorType.PROXY trước khi trả tài khoản.
  • requestTimeout có giá trị, vì mặc định không giới hạn.
  • retryAfter không thay cho thử lại lỗi mạng.
  • Không tắt verifySsl để chữa lỗi chứng chỉ.
  • Ca kiểm IP chạy đầu 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 JDK 11 và Maven. Mình chưa thử Unirest 3, chưa thử SOCKS5, chưa thử NTLM và chưa thử gateway thương mại. Một số chi tiết như cách nạp ProxySelector vào cấu hình cần đối chiếu với tài liệu và Javadoc của đúng bản Unirest đang dùng.

Nếu anh em chạy bộ ca kiểm và thấy kết quả khác, hành vi thực tế trên bản của mình là chuẩn. Ghi lại bản Unirest, bản JDK và kết quả để cả nhóm dùng chung.

Unirest Java proxy và những điều cần nhớ

Unirest Java proxy đặt ở cấu hình instance, không ở từng request. Tách instance cho tuyến ngoài và tuyến nội bộ, dùng ProxySelector khi cần chọn theo host, xử lý xác thực Basic trong đường hầm và luôn đặt requestTimeout. Cần proxy ổn định cho Unirest Java 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