خانه/مقالات/ارسال POST در جاوا با Apache HttpClient و OKHttp — راهنمای عملی برای وب اسکریپینگ
داده‌کاوی
API
پروکسی و چرخش IP
برگشت به صفحه مقاله ها
ارسال POST در جاوا با Apache HttpClient و OKHttp — راهنمای عملی برای وب اسکریپینگ

ارسال POST در جاوا با Apache HttpClient و OKHttp — راهنمای عملی برای وب اسکریپینگ

این مقاله گام‌به‌گام نحوهٔ ارسال درخواست‌های POST در Java با Apache HttpClient و OKHttp را برای JSON و فرم‌داده توضیح می‌دهد، تفاوت‌های همزمان/غیرهمزمان را روشن می‌کند و نکات عملی مرتبط با وب اسکریپینگ مانند timeout، retry، پروکسی و امنیت را به‌صورت خلاصه ارائه می‌کند.
امیر حسین حسینیان
امیر حسین حسینیان
1404-09-17

مقدمه

در این مقاله نحوهٔ ارسال درخواست‌های POST در زبان Java با دو کتابخانهٔ محبوب — Apache HttpClient (نسخهٔ 5) و OKHttp (نسخهٔ 4) — را با نگاه به کاربردهای وب اسکریپینگ توضیح می‌دهیم. مخاطب این راهنما توسعه‌دهندهٔ Python در سطح متوسط است؛ بنابراین ضمن تشریح جزئیات Java، معادل‌های سادهٔ Python با requests نیز نشان داده می‌شود تا درک مقایسه‌ای آسان‌تر شود. در پایان یاد می‌گیرید چگونه JSON و فرم‌داده ارسال کنید، تفاوت اجرای همزمان/غیرهمزمان را بفهمید و نکات عملی برای پایداری، امنیت و جلوگیری از بلاک شدن در اسکریپ را به‌کار ببرید.

POST JSON Data — Apache HttpClient

ایدهٔ کلی: ارسال payload از نوع JSON به یک endpoint معمولی در API. در HttpClient نسخهٔ 5 مثال زیر از حالت غیرهمزمان (CloseableHttpAsyncClient) استفاده می‌کند که خروجی آن یک Future<SimpleHttpResponse> است.

مراحل:

  1. وارد کردن کلاس‌های مورد نیاز
  2. ساخت و شروع CloseableHttpAsyncClient
  3. ساخت SimpleHttpRequest با تعیین body و ContentType.APPLICATION_JSON
  4. ارسال با client.execute و انتظار برای future.get()
  5. بستن client در finally برای آزادسازی منابع

مثال کامل:

import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import org.apache.hc.core5.http.ContentType;
import java.util.concurrent.Future;

public class JsonPostRequest {
    public static void main(String[] args) throws Exception {
        String requestUrl = "https://httpbin.org/post";
        String jsonData = "{\"key\": \"value\"}"; // payload JSON

        CloseableHttpAsyncClient client = HttpAsyncClients.createDefault();
        client.start();

        try {
            SimpleHttpRequest request = SimpleRequestBuilder.post(requestUrl)
                    .setBody(jsonData, ContentType.APPLICATION_JSON)
                    .build();

            Future future = client.execute(request, null);
            SimpleHttpResponse response = future.get();
            System.out.println("Response body: " + response.getBodyText());
        } finally {
            client.close();
        }
    }
}

توضیح کد:

  • requestUrl و jsonData: ورودی‌های تابع؛ URL مقصد و رشتهٔ JSON.
  • client.start(): منابع داخلی را راه‌اندازی می‌کند؛ فراموش نکنید با client.close() آنها را آزاد کنید.
  • setBody(..., ContentType.APPLICATION_JSON): کنترل Content-Type را به عهده دارد؛ سرور براساس آن JSON را تفسیر می‌کند.
  • Future<SimpleHttpResponse>: نشان‌دهندهٔ عملیات غیرهمزمان است؛ در سناریوهای اسکریپینگ می‌توانید از timeout یا cancel برای جلوگیری از بن‌بست استفاده کنید.

نکات عملی و هشدارها:

  • به جای بلاک کردن همیشگی روی future.get()، در اسکریپ‌های بزرگ از ترکیب با timeout، یا CompletableFuture برای مدیریت همزمانی استفاده کنید.
  • اگر payload بزرگ است از استریم‌ها یا chunked transfer استفاده کنید تا حافظهٔ JVM تحت فشار قرار نگیرد.

POST JSON Data — OKHttp

ایدهٔ کلی: در OKHttp نمونهٔ عادی (همزمان) رایج است اما می‌توان درخواست‌ها را به صورت غیرهمزمان هم فرستاد. ابتدا کلاینت را می‌سازیم، سپس MediaType و RequestBody را ایجاد کرده و با Request.Builder آن را ارسال می‌کنیم.

import java.util.concurrent.TimeUnit;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class JsonPostOkHttp {
    public static void main(String[] args) throws Exception {
        String requestUrl = "https://httpbin.org/post";
        String jsonData = "{\"key\": \"value\"}";

        OkHttpClient client = new OkHttpClient.Builder()
                .readTimeout(30, TimeUnit.SECONDS)
                .build();

        MediaType contentType = MediaType.get("application/json");
        RequestBody body = RequestBody.create(jsonData, contentType);

        Request request = new Request.Builder()
                .url(requestUrl)
                .post(body)
                .build();

        try (Response response = client.newCall(request).execute()) {
            System.out.println("Response body: " + response.body().string());
        }
    }
}

توضیح کد:

  • OkHttpClient.Builder().readTimeout: تنظیم timeout برای پاسخ؛ در اسکریپینگ همیشه timeout معقول تعیین کنید.
  • MediaType.get و RequestBody.create: Content-Type و بدنهٔ درخواست را می‌سازند.
  • client.newCall(request).execute(): اجرا و دریافت پاسخ به صورت همزمان؛ از بلوک try-with-resources برای بستن خودکار Response استفاده شده.

معادل سریع در Python با requests (برای مقایسه):

import requests

resp = requests.post("https://httpbin.org/post", json={"key": "value"}, timeout=30)
print(resp.text)

POST Form Data

فرمت فرم‌درخواست‌ها معمولا application/x-www-form-urlencoded است. در هر دو کتابخانه باید Content-Type مناسب را ست کنیم و بدنه را به صورت رشتهٔ کدشده یا با استفاده از کلاس‌های helper بسازیم.

Form Data — Apache HttpClient

برای HttpClient دوباره از setBody استفاده می‌کنیم ولی با ContentType.APPLICATION_FORM_URLENCODED:

// imports omitted for brevity (see previous examples)
public class FormDataPostRequest {
    public static void main(String[] args) throws Exception {
        String requestUrl = "https://httpbin.org/post";
        String formData = "key1=value1&key2=value2"; // URL-encoded string

        CloseableHttpAsyncClient client = HttpAsyncClients.createDefault();
        client.start();

        try {
            SimpleHttpRequest request = SimpleRequestBuilder.post(requestUrl)
                    .setBody(formData, ContentType.APPLICATION_FORM_URLENCODED)
                    .build();

            Future future = client.execute(request, null);
            SimpleHttpResponse response = future.get();
            System.out.println("Response body: " + response.getBodyText());
        } finally {
            client.close();
        }
    }
}

نکات:

  • رشتهٔ فرم را پیش از ارسال به‌درستی URL-encode کنید؛ در Java می‌توان از URLEncoder.encode برای تک‌مقادیر استفاده کرد.
  • در فرم‌های پیچیده‌تر از multipart برای فایل‌ها استفاده کنید تا Content-Type به multipart/form-data تغییر کند.

Form Data — OKHttp

در OKHttp محتوای فرم را با تعیین MediaType برابر با application/x-www-form-urlencoded می‌سازیم:

// imports omitted for brevity
public class FormDataPostOkHttp {
    public static void main(String[] args) throws Exception {
        String requestUrl = "https://httpbin.org/post";
        String formData = "key1=value1&key2=value2";

        OkHttpClient client = new OkHttpClient.Builder()
                .readTimeout(30, TimeUnit.SECONDS)
                .build();

        MediaType contentType = MediaType.get("application/x-www-form-urlencoded");
        RequestBody body = RequestBody.create(formData, contentType);

        Request request = new Request.Builder()
                .url(requestUrl)
                .post(body)
                .build();

        try (Response response = client.newCall(request).execute()) {
            System.out.println("Response body: " + response.body().string());
        }
    }
}

مقایسهٔ سریع و مزایا/معایب

  • Apache HttpClient (async): مناسب برای اسکریپ‌هایی که نیاز به همزمانی غیرهمزمان، connection pooling و کنترل ریزتر بر رفتار HTTP دارند. اما تنظیمات اولیه پیچیده‌تر است.
  • OKHttp: ساده، کم‌حجم و برای درخواست‌های همزمان گزینهٔ مناسبی است؛ API دوستانه و مدیریت خودکار connection pooling. در صورتی که نیاز به async پیچیده دارید باید از callback یا wrapperهای اضافی استفاده کنید.

مزایا و معایب کوتاه:

  • HttpClient: + کنترل جزئی‌تر، پشتیبانی قوی از async. - پیچیدگی بیشتر.
  • OKHttp: + ساده و سریع برای توسعه. - در حالت async به callbackها وابسته است یا باید از executor استفاده کنید.

نکات مربوط به وب اسکریپینگ، پایداری و امنیت

  • همیشه هدرهای لازم را (مثل User-Agent) ست کنید تا رفتار شبیه مرورگر داشته باشید، اما از جعل هویت سوءاستفاده نکنید.
  • برای جلوگیری از بلاک شدن: محدودیت نرخ (rate limiting)، استفاده از پروکسی‌ها، پراکسی چرخان و randomized delays را در نظر بگیرید.
  • در مدیریت خطا از retry با backoff نمایی استفاده کنید و خطاهای قابل بازیافت (۵xx، timeouts) را تفکیک کنید.
  • اعتبارسنجی گواهی TLS را دست‌کم نگیرید؛ غیرفعال‌کردنش خطرناک است. در مواقع ضروری از ارسال CA خاص یا پیکربندی SSLContext استفاده کنید.
  • برای payloadهای بزرگ و دانلودها از streaming استفاده کنید تا حافظهٔ سرور یا کلاینت اشباع نشود.
  • اطلاعات حساس (توکن‌ها، کوکی‌ها) را در لاگ‌های production ننویسید و آن‌ها را ایمن ذخیره کنید.

توصیه‌های پیاده‌سازی در پروژه‌های Python که با سرویس‌های Java تعامل دارند

اگر در اکوسیستم Python هستید و با سرویس‌های نوشته‌شده در Java تعامل دارید، معمولاً کافی است از requests برای POST JSON یا فرم استفاده کنید. اما برای تست یا مقایسه رفتار، دانستن تفاوت‌های پیش‌فرضی مانند headerهای اضافه‌شده، اتصال‌های keep-alive و مدیریت زمان‌بندی در کتابخانه‌های Java مفید است.

# مثال معادل ارسال فرم در Python
import requests

resp = requests.post("https://httpbin.org/post",
                     data={"key1": "value1", "key2": "value2"},
                     headers={"User-Agent": "my-scraper/1.0"},
                     timeout=30)
print(resp.text)

جمع‌بندی

در این راهنما شیوه‌های مرسوم ارسال درخواست‌های POST با Apache HttpClient و OKHttp را برای JSON و فرم‌داده توضیح دادیم و نکات عملی برای استفاده در وب اسکریپینگ را مرور کردیم. انتخاب بین این دو بستگی به نیاز شما به کنترل ریز، همزمانی و سادگی API دارد. در نهایت همیشه timeout، مدیریت منابع (بستن کلاینت/پاسخ)، و سیاست‌های retry را در پیاده‌سازی‌ اسکریپ‌هایتان در نظر بگیرید.

مقاله‌های مرتبط