عميل HTTP بلغة Rust: تقنيات متقدمة وأفضل الممارسات

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا عميل HTTP المتقدم بلغة Rust مهم

لقد اكتسبت Rust سمعة كلغة للأنظمة التي تتطلب أداءً وموثوقية عالية. ومع ذلك، عند كتابة عميل HTTP بلغة Rust، يتوقف العديد من المطورين عند الأمثلة الأساسية من التوثيق. في المشاريع الحقيقية - الخدمات المصغرة، المحللات، أدوات CI/CD - الاستدعاء البسيط reqwest::get() لا يصمد أمام النقد. الأعطال بسبب أخطاء الشبكة، التجميد عند الاستجابات الطويلة، تسرب الاتصالات - كلها نتائج لنهج سطحي.

في هذه المقالة، سنستعرض المستوى المتقدم للعمل مع عميل HTTP بلغة Rust. ستتعلم كيفية معالجة الأخطاء بشكل صحيح، ضبط المهلات الزمنية، تنفيذ آلية إعادة المحاولة (retries) وإدارة TLS. جميع الأمثلة مكتوبة بلغة Rust باستخدام crate reqwest و tokio - المكدس القياسي لطلبات HTTP غير المتزامنة.



1. معالجة الأخطاء في عميل HTTP بلغة Rust

أي طلب شبكي قد يفشل: انقطاع الاتصال، خطأ DNS، حالة استجابة غير صحيحة. في Rust، يُستخدم نظام الأنواع القوي Result و Error لهذا الغرض. النهج المتقدم هو ليس فقط التحقق من الحالة، بل تسجيل الأخطاء وتصنيفها.



معالجة الأخطاء المنظمة

لننشئ نوع خطأ مخصص لعميل HTTP:

use std::fmt;use reqwest::StatusCode;

#[derive(Debug)]pub enum HttpClientError { NetworkError(reqwest::Error), BadStatus(StatusCode), Timeout, InvalidUrl(String),}

impl fmt::Display for HttpClientError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { HttpClientError::NetworkError(e) => write!(f, "خطأ شبكي: {}", e), HttpClientError::BadStatus(s) => write!(f, "حالة غير صحيحة: {}", s), HttpClientError::Timeout => write!(f, "مهلة الطلب"), HttpClientError::InvalidUrl(url) => write!(f, "URL غير صحيح: {}", url), } }}

impl From<reqwest::Error> for HttpClientError { fn from(e: reqwest::Error) -> Self { if e.is_timeout() { HttpClientError::Timeout } else if e.is_connect() { HttpClientError::NetworkError(e) } else { HttpClientError::NetworkError(e) } }}


الآن دالة الطلب تُرجع خطأً مصنفاً بوضوح:

async fn fetch_data(url: &str) -> Result<String, HttpClientError> {    if !url.starts_with("http") {        return Err(HttpClientError::InvalidUrl(url.to_string()));    }

let response = reqwest::get(url).await?;

match response.status() { StatusCode::OK => { let body = response.text().await?; Ok(body) } status => Err(HttpClientError::BadStatus(status)), }}


هذا النهج يسمح للكود المستدعي بمعرفة ما حدث بالضبط واتخاذ القرارات الصحيحة: إعادة الطلب عند خطأ شبكي، ولكن ليس عند 400 Bad Request.



2. المهلات الزمنية وإدارة الاتصال

بدون مهلات زمنية، قد يتجمد عميل HTTP الخاص بك بلغة Rust لدقائق. الإعداد المتقدم يشمل ثلاثة مستويات: مهلة الاتصال، مهلة القراءة، والمهلة الإجمالية للطلب بأكمله.



إعداد العميل مع المهلات الزمنية

use std::time::Duration;use reqwest::Client;

async fn create_advanced_client() -> Result<Client, reqwest::Error> { let client = Client::builder() .timeout(Duration::from_secs(30)) // المهلة الإجمالية .connect_timeout(Duration::from_secs(5)) // مهلة الاتصال .pool_max_idle_per_host(10) // الحد الأقصى للاتصالات الخاملة .tcp_keepalive(Duration::from_secs(60)) // keepalive .build()?;

Ok(client)}


الآن نستخدم العميل مع المهلات الزمنية في الواقع

المدونات

توصيات الكتب