記一次HttpClient使用問題分析

louzi發表於2024-09-21

問題

問題是這樣的:第三方的webapi,需要先呼叫登陸介面獲取Cookie,訪問其它介面時攜帶Cookie資訊。

但使用HttpClient類呼叫登陸介面,返回的Headers中沒有找到Cookie資訊。

分析

首先,使用Postman測試該登陸介面,正常返回Cookie資訊,說明是HttpClient訪問介面出了問題。

透過除錯發現,明明使用的Post請求,返回的HttpResponseMessage卻顯示為GET請求。

下載WireShark網路分析工具,抓包發現,Post請求返回了302,且返回中是攜帶了Cookie資訊的,隨即又進行了GET請求到重定向的地址,返回的資訊中沒有Cookie。302表示請求的資源已被臨時移動到另一個位置,客戶端應該重定向到的新位置。因此,可以知道是HttpClient自動進行了重定向。

解決

方法也很簡單,對於登陸介面,直接禁用自動跟隨重定向即可:

public async Task<HttpResponseMessage> PostAuthAsync(string url, CancellationToken cancellationToken = default(CancellationToken))
{
    using var httpClientHandler = new HttpClientHandler()
    {
        // 禁用自動跟隨重定向
        AllowAutoRedirect = false
    };

    using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, url);
    using var client = new HttpClient(httpClientHandler);
    return await client.SendAsync(request, cancellationToken);
}

從返回中獲取指定的Cookie資訊:

string GetCookieFromResponseHeader(HttpResponseHeaders headers)
{
    if (headers.TryGetValues("Set-Cookie", out IEnumerable<string> setCookieHeaders))
    {
        foreach (var headerValue in setCookieHeaders)
        {
            foreach (var cookieHeader in headerValue.Split(';'))
            {
                var parts = cookieHeader.Split('=');
                if (parts.Length == 2 && parts[0] == cookieName)
                    return parts[1];
            }
        }
    }

    return string.Empty;
}

訪問其它介面時,新增Cookie資訊:

public async Task<HttpResponseMessage> PostAsync(string url, string cookie, string jsonData, CancellationToken cancellationToken = default(CancellationToken))
{
    var content = new StringContent(jsonData, Encoding.UTF8, "application/json");
    var httpClient = _httpClientFactory.CreateClient();
    string cookieHeader = $"{cookieName}={cookie}";
    httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Cookie", cookieHeader);
    return await httpClient.PostAsync(url, content, cancellationToken);
}

相關文章