.NET Core Httpclient 有效,但 .Net Framework 4.7.2 httpclient 无效

Posted

技术标签:

【中文标题】.NET Core Httpclient 有效,但 .Net Framework 4.7.2 httpclient 无效【英文标题】:.NET Core Httpclient works but .Net Framework 4.7.2 httpclient doesn't 【发布时间】:2019-08-06 13:39:47 【问题描述】:

抱歉,标题很糟糕,我不确定如何用简短的标题格式来表达我的问题。

我正在尝试与外部 API 进行通信。我向该 API 发出基本身份验证请求,并从 api 获取 x-csrf-token 和会话令牌。

然后我向该 API 发出另一个请求,现在使用 x-csrf-token 作为标头,并将会话令牌作为“cookie”附加到标头。

维护 API 的团队向我发送了一个处理上述所有内容的示例项目,它看起来像这样:

public static async Task<string> Send(string apiname, string value)

    // Fetch the authorization tokens from SAP
    HttpClient client = new HttpClient();
    client.BaseAddress = new Uri(basePath);
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(user + ":" + password)));
    client.DefaultRequestHeaders.Add("x-csrf-token", "Fetch");
    string csrfToken = "";
    string sessionCookie = "";
    HttpResponseMessage response = await client.GetAsync(string.Empty);
    IEnumerable<string> values;
    if (response.Headers.TryGetValues("x-csrf-token", out values))
    
        csrfToken = values.FirstOrDefault();
    
    if (response.Headers.TryGetValues("set-cookie", out values))
    
        sessionCookie = values.Where(s => s.StartsWith("SAP_SESSION")).FirstOrDefault();
    

    // Reinstantiate the HttpClient, adding the tokens we just got from SAP
    client = new HttpClient();
    client.DefaultRequestHeaders.Add("x-csrf-token", csrfToken);
    client.DefaultRequestHeaders.Add("cookie", sessionCookie);
    client.BaseAddress = new Uri(basePath);
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    // Have to parse the string this way otherwise it'll break the dates
    JToken token;
    using (var sr = new StringReader(value))
    using (var jr = new JsonTextReader(sr)  DateParseHandling = DateParseHandling.None )
    
        token = JToken.ReadFrom(jr);
    
    HttpResponseMessage response2 = await client.PostAsJsonAsync(apiname, token);
    string responseBody = await response2.Content.ReadAsStringAsync();
    return responseBody;

这一切都非常适合作为 .NET Core webAPI(以及 .netcore 控制台应用程序)。

有趣的是(无论如何在我看来),当我在 .net 4.7.2 项目中使用完全相同的代码时,它没有正确附加“cookie”标头,因此我得到了未经授权的重定向来自 API。

为了绝对确保我没有更改任何代码,我从头开始使用全新的 .netcore 2.0 控制台应用程序和全新的 .net 4.7.2 控制台应用程序并复制粘贴完全相同的代码并安装相同的 nuget 包(Newtonsoft.JSON 和 Microsoft.WebApi.Client)。我用提琴手检查了我的网络流量(见下文),您可以看到在 .netcore 中,cookie 正确附加并且一切正常,但在 .net 4.7.2 中,API 返回重定向以进行身份​​验证。

【问题讨论】:

【参考方案1】:

如果你不将UseCookies设置为false,HttpClient会吃掉自定义cookie,

using (var handler = new HttpClientHandler  UseCookies = false )
using (client = new HttpClient(handler)  BaseAddress = new Uri(Path) )
      client.DefaultRequestHeaders.Add("cookie", cookieValue);

它将尝试使用 cookie 容器,同时忽略任何自定义 cookie 标头,如果您问我,这是非常令人沮丧的行为。

【讨论】:

【参考方案2】:

.Net Framework 使用 Cookie 容器。

也是核心,也许它比你现在正在做的更好的实现和更多的支持。

Please see cookie container docs

小例子:

  var cookieContainer = new CookieContainer();
            this.handler = new HttpClientHandler
            
                CookieContainer = cookieContainer,
                UseCookies = true
            ;
            client = new HttpClient(handler);

【讨论】:

我认为这是在正确的路径上,但我的 cookie 有多个分号分隔的值,所以当我向 cookieContainer 添加新 cookie 时,它​​会显示“cookie 的值部分无效”,但如果我对 cookie 进行编码以绕过该错误,我们的 API 将无法正常工作。 考虑到 fiddler/chrome/API 可以使用 cookie 但 CookieContainer 不行,有没有办法以 cookieContainer 不会爆炸的方式添加 cookie?

以上是关于.NET Core Httpclient 有效,但 .Net Framework 4.7.2 httpclient 无效的主要内容,如果未能解决你的问题,请参考以下文章

在 c# (.net core) 中使用 httpclient 时无法建立 SSL 连接,但在 Postman 和 Browser 中有效

你能用.Net Core HttpClient实现Http/2多路复用吗?

Httpclient在.net core3.1上成功运行,但更新到.net 5中连接超时(System.Net.Sockets.SocketException (10060)) C#

ASP.NET Core HttpClient 请求在 webapi 返回 406 时返回 200

.NET CORE HttpClient使用

asp.net core 使用HttpClientFactory Polly实现熔断降级