欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#封裝HttpClient實(shí)現(xiàn)HTTP請(qǐng)求處理

 更新時(shí)間:2025年06月06日 11:06:33   作者:阿蒙Armon  
HttpClient作為.NET框架中處理HTTP請(qǐng)求的核心組件,為我們提供了強(qiáng)大而靈活的API,本文將介紹一個(gè)完整的HttpRequest類封裝實(shí)現(xiàn),并深入探討HTTP請(qǐng)求處理的最佳實(shí)踐

在現(xiàn)代的.NET應(yīng)用程序開發(fā)中,與外部服務(wù)進(jìn)行HTTP通信是一項(xiàng)常見需求。HttpClient作為.NET框架中處理HTTP請(qǐng)求的核心組件,為我們提供了強(qiáng)大而靈活的API。然而,直接使用原生的HttpClient可能會(huì)導(dǎo)致代碼重復(fù)、錯(cuò)誤處理不完善等問題。為了提高代碼的可維護(hù)性和可測試性,我們通常會(huì)對(duì)HttpClient進(jìn)行封裝。本文將介紹一個(gè)完整的HttpRequest類封裝實(shí)現(xiàn),并深入探討HTTP請(qǐng)求處理的最佳實(shí)踐。

一、完整的HttpRequest類實(shí)現(xiàn)

首先,讓我們來看一下完整的HttpRequest類實(shí)現(xiàn)代碼:

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

???????public class Response
{
    public bool Success { get; set; }
    public string Message { get; set; }
    public object Data { get; set; }
    public HttpStatusCode StatusCode { get; set; }
}

public static class JsonConverterExtensions
{
    public static readonly JsonSerializerOptions SerializerSettings = new JsonSerializerOptions
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        IgnoreNullValues = true,
        WriteIndented = false
    };
}

public class HttpRequest : IDisposable
{
    private readonly HttpClient client;
    private bool disposed = false;
    
    public HttpRequest(HttpClient client)
    {
        this.client = client ?? throw new ArgumentNullException(nameof(client));
    }
    
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    
    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                client?.Dispose();
            }
            disposed = true;
        }
    }
    
    public async Task<Response> GetAsync(string resource)
    {
        try
        {
            var response = await client.GetAsync(resource);
            return await ProcessResponseAsync(response);
        }
        catch (HttpRequestException ex)
        {
            return HandleException(ex);
        }
        catch (Exception ex)
        {
            return HandleUnexpectedException(ex);
        }
    }
    
    public async Task<Response> PostAsync(string resource, object body)
    {
        try
        {
            var content = CreateJsonContent(body);
            var response = await client.PostAsync(resource, content);
            return await ProcessResponseAsync(response);
        }
        catch (HttpRequestException ex)
        {
            return HandleException(ex);
        }
        catch (Exception ex)
        {
            return HandleUnexpectedException(ex);
        }
    }
    
    public async Task<Response> PutAsync(string resource, object body)
    {
        try
        {
            var content = CreateJsonContent(body);
            var response = await client.PutAsync(resource, content);
            return await ProcessResponseAsync(response);
        }
        catch (HttpRequestException ex)
        {
            return HandleException(ex);
        }
        catch (Exception ex)
        {
            return HandleUnexpectedException(ex);
        }
    }
    
    public async Task<Response> DeleteAsync(string resource)
    {
        try
        {
            var response = await client.DeleteAsync(resource);
            return await ProcessResponseAsync(response);
        }
        catch (HttpRequestException ex)
        {
            return HandleException(ex);
        }
        catch (Exception ex)
        {
            return HandleUnexpectedException(ex);
        }
    }
    
    public HttpRequest WithBaseAddress(string baseAddress)
    {
        if (!string.IsNullOrEmpty(baseAddress))
        {
            client.BaseAddress = new Uri(baseAddress);
        }
        return this;
    }
    
    public HttpRequest WithTimeout(TimeSpan timeout)
    {
        client.Timeout = timeout;
        return this;
    }
    
    public HttpRequest WithHeader(string name, string value)
    {
        if (!client.DefaultRequestHeaders.Contains(name))
        {
            client.DefaultRequestHeaders.Add(name, value);
        }
        return this;
    }
    
    public HttpRequest WithHeaders(IDictionary<string, string> headers)
    {
        if (headers != null)
        {
            foreach (var header in headers)
            {
                WithHeader(header.Key, header.Value);
            }
        }
        return this;
    }
    
    public HttpRequest WithAuthorization(string scheme, string parameter)
    {
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(scheme, parameter);
        return this;
    }
    
    public HttpRequest WithBearerToken(string token)
    {
        return WithAuthorization("Bearer", token);
    }
    
    private StringContent CreateJsonContent(object body)
    {
        if (body == null)
        {
            return new StringContent("{}", Encoding.UTF8, "application/json");
        }
        
        var json = JsonSerializer.Serialize(body, JsonConverterExtensions.SerializerSettings);
        return new StringContent(json, Encoding.UTF8, "application/json");
    }
    
    private async Task<Response> ProcessResponseAsync(HttpResponseMessage response)
    {
        var responseContent = await response.Content.ReadAsStringAsync();
        
        try
        {
            // 嘗試解析JSON響應(yīng)
            var responseObject = JsonSerializer.Deserialize<Response>(responseContent, JsonConverterExtensions.SerializerSettings);
            
            if (responseObject != null)
            {
                responseObject.StatusCode = response.StatusCode;
                return responseObject;
            }
        }
        catch (JsonException)
        {
            // 如果JSON解析失敗,創(chuàng)建一個(gè)基于HTTP狀態(tài)碼的響應(yīng)
        }
        
        // 對(duì)于非JSON響應(yīng)或解析失敗的情況
        return new Response
        {
            Success = response.IsSuccessStatusCode,
            Message = response.ReasonPhrase,
            StatusCode = response.StatusCode,
            Data = responseContent
        };
    }
    
    private Response HandleException(HttpRequestException ex)
    {
        return new Response
        {
            Success = false,
            Message = $"HTTP請(qǐng)求錯(cuò)誤: {ex.Message}",
            StatusCode = ex.StatusCode ?? HttpStatusCode.InternalServerError,
            Data = ex
        };
    }
    
    private Response HandleUnexpectedException(Exception ex)
    {
        return new Response
        {
            Success = false,
            Message = $"處理請(qǐng)求時(shí)發(fā)生意外錯(cuò)誤: {ex.Message}",
            StatusCode = HttpStatusCode.InternalServerError,
            Data = ex
        };
    }
}

二、設(shè)計(jì)思路與實(shí)現(xiàn)要點(diǎn)

1. 依賴注入與生命周期管理

這個(gè)封裝類采用了依賴注入模式,通過構(gòu)造函數(shù)接收一個(gè)HttpClient實(shí)例。這樣做有幾個(gè)重要好處:

遵循單一職責(zé)原則,HttpRequest類專注于HTTP請(qǐng)求處理

便于單元測試,可以輕松注入模擬的HttpClient

利用.NET的IHttpClientFactory進(jìn)行正確的HttpClient生命周期管理,避免資源泄漏

同時(shí),類實(shí)現(xiàn)了IDisposable接口,確保在不再需要時(shí)正確釋放HttpClient資源。

2. 流暢接口設(shè)計(jì)

為了提供更友好的API體驗(yàn),封裝類實(shí)現(xiàn)了流暢接口模式:

var response = await new HttpRequest(httpClient)
    .WithBaseAddress("https://api.example.com")
    .WithBearerToken("your-token-here")
    .WithHeader("X-Custom-Header", "value")
    .PostAsync("/resource", new { Key = "value" });

這種鏈?zhǔn)秸{(diào)用方式使代碼更加簡潔易讀,同時(shí)保持了良好的可擴(kuò)展性。

3. 統(tǒng)一的錯(cuò)誤處理

在每個(gè)HTTP方法中,我們都實(shí)現(xiàn)了統(tǒng)一的異常處理機(jī)制:

  • 捕獲HttpRequestException處理HTTP特定錯(cuò)誤
  • 捕獲其他異常處理意外錯(cuò)誤
  • 將所有錯(cuò)誤轉(zhuǎn)換為統(tǒng)一的Response對(duì)象
  • 保留原始異常信息以便調(diào)試

這種統(tǒng)一的錯(cuò)誤處理方式使上層調(diào)用代碼更加簡潔,無需重復(fù)處理各種異常情況。

4. 靈活的響應(yīng)處理

ProcessResponseAsync方法負(fù)責(zé)處理HTTP響應(yīng),它嘗試將響應(yīng)內(nèi)容解析為JSON格式的Response對(duì)象:

  • 如果解析成功,返回包含完整信息的Response對(duì)象
  • 如果解析失敗,創(chuàng)建一個(gè)基于HTTP狀態(tài)碼的Response對(duì)象
  • 始終保留原始響應(yīng)內(nèi)容和狀態(tài)碼信息

這種設(shè)計(jì)使封裝類能夠處理各種類型的HTTP響應(yīng),同時(shí)提供一致的返回格式。

三、實(shí)際使用示例

下面是一個(gè)使用這個(gè)封裝類的完整示例:

using System;
using System.Net.Http;
using System.Threading.Tasks;

???????public class Program
{
    public static async Task Main()
    {
        try
        {
            // 創(chuàng)建HttpClient實(shí)例(實(shí)際應(yīng)用中建議使用IHttpClientFactory)
            using var httpClient = new HttpClient();
            
            // 創(chuàng)建請(qǐng)求實(shí)例并配置
            var request = new HttpRequest(httpClient)
                .WithBaseAddress("https://api.example.com")
                .WithBearerToken("your-auth-token");
                
            // 發(fā)送GET請(qǐng)求
            var getResponse = await request.GetAsync("/api/users");
            Console.WriteLine($"GET請(qǐng)求結(jié)果: {getResponse.Success}, 狀態(tài)碼: {getResponse.StatusCode}");
            
            // 發(fā)送POST請(qǐng)求
            var postData = new { Name = "John Doe", Email = "john@example.com" };
            var postResponse = await request.PostAsync("/api/users", postData);
            Console.WriteLine($"POST請(qǐng)求結(jié)果: {postResponse.Success}, 狀態(tài)碼: {postResponse.StatusCode}");
            
            // 發(fā)送PUT請(qǐng)求
            var putData = new { Id = 1, Name = "Jane Doe" };
            var putResponse = await request.PutAsync("/api/users/1", putData);
            Console.WriteLine($"PUT請(qǐng)求結(jié)果: {putResponse.Success}, 狀態(tài)碼: {putResponse.StatusCode}");
            
            // 發(fā)送DELETE請(qǐng)求
            var deleteResponse = await request.DeleteAsync("/api/users/1");
            Console.WriteLine($"DELETE請(qǐng)求結(jié)果: {deleteResponse.Success}, 狀態(tài)碼: {deleteResponse.StatusCode}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"發(fā)生未處理的異常: {ex.Message}");
        }
    }
}

四、HttpClient使用最佳實(shí)踐

在使用HttpClient和這個(gè)封裝類時(shí),還需要注意以下最佳實(shí)踐:

  • 使用IHttpClientFactory:在ASP.NET Core應(yīng)用中,始終使用IHttpClientFactory創(chuàng)建HttpClient實(shí)例,避免直接實(shí)例化HttpClient。
  • 設(shè)置合理的超時(shí)時(shí)間:默認(rèn)情況下,HttpClient的超時(shí)時(shí)間是100秒,根據(jù)實(shí)際需求調(diào)整這個(gè)值,防止長時(shí)間阻塞。
  • 處理取消請(qǐng)求:考慮實(shí)現(xiàn)請(qǐng)求取消機(jī)制,通過CancellationToken參數(shù)傳遞取消令牌。
  • 處理重試邏輯:對(duì)于臨時(shí)性網(wǎng)絡(luò)錯(cuò)誤,考慮實(shí)現(xiàn)重試機(jī)制??梢允褂肞olly等庫來簡化重試策略的實(shí)現(xiàn)。
  • 監(jiān)控HTTP請(qǐng)求性能:記錄HTTP請(qǐng)求的執(zhí)行時(shí)間、成功率等指標(biāo),便于性能分析和問題排查。

通過這個(gè)完整的HttpRequest類封裝,我們可以更加高效、安全地處理HTTP通信,同時(shí)保持代碼的整潔和可維護(hù)性。希望這篇文章對(duì)你理解C#中的HTTP請(qǐng)求處理有所幫助。

這個(gè)實(shí)現(xiàn)提供了完整的HTTP請(qǐng)求功能,包括GET、POST、PUT、DELETE方法,以及靈活的請(qǐng)求配置和統(tǒng)一的響應(yīng)處理。

到此這篇關(guān)于C#封裝HttpClient實(shí)現(xiàn)HTTP請(qǐng)求處理的文章就介紹到這了,更多相關(guān)C#封裝HttpClient內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論