我正在使用HttpClient
来消费一个网站。网站使用cookie,但其中一个cookie没有分配path
数据。HttpClient将使用请求文件的相对路径作为路径信息,而浏览器仅使用目录信息。
示例:
Request-URL:
https://someurl.org/dir1/file.php
HttpClient:
path=/dir1/file.php
browser:
path=/dir1
C#行为是有问题的,因为cookie只会发送到特定的文件,而不是同一目录中的所有文件。作为一种变通方法,我提取cookie,制作一个副本,为副本分配正确的路径,将原始文件标记为过期,然后将副本添加到cookie容器中。
这是可行的,但在这种情况下,可能有一个更好、更正式的选项可以让HttpClient像浏览器一样运行?
这个问题与我自己的问题非常相似(而不是直接使用HttpClient
(我的场景(HttpWebRequest
(,它也为问题提供了更多的背景信息。
尽管我最终没有得到那里提供的解决方案,但我确实修改了这个问题的答案,以扩展DelegatingHandler
并自己管理cookie(如果缺少路径信息,通过插入路径信息来解决问题(,而不是让HttpMessageHandler
处理cookie。
public class FixMissingPathOnPlainCookiesHandler : DelegatingHandler
{
public CookieContainer Container { get; private set; }
public FixMissingPathOnPlainCookiesHandler(HttpClientHandler clientHandler, CookieContainer cc = null)
: base(clientHandler)
{
if (clientHandler == null)
throw new ArgumentNullException(nameof(clientHandler));
if (clientHandler.UseCookies)
throw new InvalidOperationException("The HttpClientHandler property '.UseCookies' must be false");
Container = cc ?? new CookieContainer();
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var uri = request.RequestUri;
var cookies = Container.GetCookieHeader(uri);
if (!string.IsNullOrEmpty(cookies))
request.Headers.Add("Cookie", cookies);
var response = await base.SendAsync(request, cancellationToken);
if (response.Headers.TryGetValues("Set-Cookie", out var cookieHeaders))
{
foreach (var cookie in cookieHeaders)
{
var local = cookie;
if (local.IndexOf("path=", StringComparison.InvariantCultureIgnoreCase) == -1)
local += "; path=" + uri.AbsolutePath.Substring(0, uri.AbsolutePath.LastIndexOf('/'));
Container.SetCookies(uri, local);
}
}
return response;
}
}