.Net HttpClient 使用 Cookie

Cookie 是服务器存储在客户端的小型数据片段,可用于身份验证、会话跟踪等。

.Net HttpClient 支持 Cookie 功能,本教程详细介绍了Cookie 的管理与使用。

初始化

csharp 复制代码
#!import "./Ini.ipynb"

Cookie 是服务器发送到用户浏览器并存储在本地的一小段数据,用来进行会话管理(如登录状态)、个性化设置(如主题偏好)、跟踪用户行为等功能。

如果只在简单的使用Cookie,想保持简洁、灵活。可以手管理。

发送带Cookie的请求

  • 不使用Cookie
csharp 复制代码
{   //不使用Cookie
    using (var client = new HttpClient(){BaseAddress=new Uri(webApiBaseUrl)})
    {
        var response = await client.GetAsync("/api/Cookie/GetRequestCookie"); 

        //确保请求成功
        response.EnsureSuccessStatusCode();

        //读取响应内容
        var content = await response.Content.ReadAsStringAsync();

        //输出 响应内容
        Console.WriteLine(content);
    }
}
  • 手动设置Cookie: 在默认请求头中添加Cookie,适合快捷请求方法(Get,Post,Put,Delete等)
csharp 复制代码
{   //多次请求时,都自动携带默认请求头Cookie

    var client = new HttpClient()
    {
        BaseAddress = new Uri(webApiBaseUrl),
    };

    //全局设置Cookie,所有快捷请求(Send方法的快捷方法:Get、Post、Put等)都会带上这个Cookie
    //快捷方法,不能单独设置Cookie; 只有Send方法才可以单独设置Cookie
    client.DefaultRequestHeaders.Add("Cookie", "Client=PolyglotNotebook,User=andy");

    //请求1
    var response = await client.GetAsync("/api/Cookie/GetRequestCookie"); 

    //确保请求成功
    response.EnsureSuccessStatusCode();

    //读取响应内容
    var content = await response.Content.ReadAsStringAsync();

    //输出 响应内容
    Console.WriteLine(content);

    //再次快捷请求,不用重新设置
    //请求2
    var response2 = await client.GetAsync("/api/Cookie/GetRequestCookie"); 

    //确保请求成功
    response2.EnsureSuccessStatusCode();

    //读取响应内容
    var content2 = await response2.Content.ReadAsStringAsync();

    //输出 响应内容
    Console.WriteLine(content2);

}
  • 手动设置Cookie:每次请求设置 HttpRequestMessage,适合Send通用方法。当然可以合并默认请求头
csharp 复制代码
{   //手动设置Cookie, 单次HttpRequestMessage合并默认请求头Cookie

    var client = new HttpClient()
    {
        BaseAddress = new Uri(webApiBaseUrl),
    };

    //全局设置Cookie,所有请求都会带上这个Cookie
    client.DefaultRequestHeaders.Add("Cookie", "Client=PolyglotNotebook,User=andy");

    //单请求设置
    var requestMessage = new HttpRequestMessage(HttpMethod.Get, "/api/Cookie/GetRequestCookie");
    
    //设置Cookie,会覆盖HttpClient设置的默认Cookie
    requestMessage.Headers.Add("Cookie", "Password=MyPassword,Role=Admin");
    //添加默认
    if(client.DefaultRequestHeaders.Contains("Cookie"))
    {
        requestMessage.Headers.Add("Cookie", client.DefaultRequestHeaders.GetValues("Cookie"));
    }

    var response = await client.SendAsync(requestMessage);
    var content = await response.Content.ReadAsStringAsync();
    Console.WriteLine(content);

    //响应头也会自动带上Cookie
    if(response.Headers.Contains("cookie"))
    {
        Console.Write($"响应头中Cookie为:");
        var cookies = response.Headers.GetValues("cookie");
        foreach (var cookie in cookies)
        {
            Console.WriteLine($"{cookie}");
        }
    }
    else
    {
        Console.WriteLine($"响应头中没有Cookie");
    }
}

查看响应头中的Cookie

csharp 复制代码
{   //获取响应头中的Cookie

    var client = new HttpClient()
    {
        BaseAddress = new Uri(webApiBaseUrl),
    };

    var response = await client.GetAsync("/api/Cookie/GetResponseCookie");

    //获取响应头中的Cookie
    if(response.Headers.Contains("cookie"))
    {
        Console.Write($"响应头中Cookie为:");
        var cookies = response.Headers.GetValues("cookie");
        foreach (var cookie in cookies)
        {
            Console.WriteLine($"{cookie}");
        }
    }
    else
    {
        Console.WriteLine($"响应头中没有Cookie");
    }
}

.NET 提供了 HttpClientHandler + CookieContainer 来自动管理 Cookie 生命周期和持久化。

使用 CookieContainer

csharp 复制代码
{
    var handler = new HttpClientHandler()
    {
        UseCookies = true,
        CookieContainer = new CookieContainer(),
    };

    using var client = new HttpClient(handler)
    {
        BaseAddress = new Uri(webApiBaseUrl),
    };

    // 第一次请求,服务端设置 Cookie
    var response = await client.GetAsync("/api/Cookie/GetResponseCookie");
    response.EnsureSuccessStatusCode();

    // 第二次请求,自动携带之前设置的 Cookie
    var response2 = await client.GetAsync("/api/Cookie/GetRequestCookie");
    var content2 = await response2.Content.ReadAsStringAsync();
    Console.WriteLine(content2);
}

若需要在程序重启后继续使用 Cookie,可将其序列化保存至文件或数据库。

  • 保存 Cookie 到文件
csharp 复制代码
///<summary
/// 保存Cookie到文件
///</summary>
public void SaveCookies(CookieContainer container, string filePath)
{
    using (var writer = new StreamWriter(filePath))
    {
        foreach (Cookie cookie in container.GetCookies(new Uri(webApiBaseUrl)))
        {
            writer.WriteLine($"{cookie.Name}={cookie.Value};Domain={cookie.Domain};Path={cookie.Path};Expires={cookie.Expires}");
        }
    }
}

//应用
{
    var handler = new HttpClientHandler()
    {
        UseCookies = true,
        CookieContainer = new CookieContainer(),
    };

    using (var client = new HttpClient(handler))
    {
        client.BaseAddress = new Uri(webApiBaseUrl);

        // 第一次请求,服务端设置 Cookie
        var response = await client.GetAsync("/api/Cookie/GetResponseCookie");
        response.EnsureSuccessStatusCode();

        SaveCookies(handler.CookieContainer, "cookies.txt");
    }
}
  • 从文件中加载 Cookie
csharp 复制代码
 <summary>
/// 从文件中加载 Cookie
/// </summary>
public CookieContainer LoadCookies(string filePath)
{
    var container = new CookieContainer();
    if (!File.Exists(filePath)) return container;

    foreach (var line in File.ReadAllLines(filePath))
    {
        var parts = line.Split(';');
        var nameValue = parts[0].Split('=');
        var cookie = new Cookie(nameValue[0], nameValue[1])
        {
            Domain = parts[1].Replace("Domain=", "").Trim(),
            Path = parts[2].Replace("Path=", "").Trim(),
            Expires = DateTime.Parse(parts[3].Replace("Expires=", "").Trim())
        };
        container.Add(cookie);
    }

    return container;
}

//发送请求:从文件中加载 Cookie, 在请求中携带
{
    var cookieBox = LoadCookies("cookies.txt");

    var handler = new HttpClientHandler()
    {
        UseCookies = true,
        CookieContainer = cookieBox,
    };

    var client = new HttpClient(handler)
    {
        BaseAddress = new Uri(webApiBaseUrl)
    };

    // 第一次请求,服务端设置 Cookie
    var response = await client.GetAsync("/api/Cookie/GetRequestCookie");
    response.EnsureSuccessStatusCode();

    var content = await response.Content.ReadAsStringAsync();

    Console.WriteLine(content);
}

默认情况下,CookieContainer 会根据域名自动隔离 Cookie。若需跨域共享 Cookie,可通过以下方式实现:

  • 手动复制 Cookie
csharp 复制代码
//示例代码,无实际请求
var sourceUri = new Uri("https://source.com");
var targetUri = new Uri("https://target.com");

foreach (Cookie cookie in handler.CookieContainer.GetCookies(sourceUri))
{
    var crossDomainCookie = new Cookie(cookie.Name, cookie.Value, cookie.Path, targetUri.Host);
    handler.CookieContainer.Add(targetUri, crossDomainCookie);
}
  • 自定义 CookieContainer(高级)
    可以继承 CookieContainer 并重写相关方法以实现自定义 Cookie 共享策略。

进阶功能:Cookie 过期、安全标志、SameSite 设置等

  • 设置 Cookie 高级属性
csharp 复制代码
{
    //发送请求
    {
        var handler = new HttpClientHandler()
        {
            UseCookies = true,
            CookieContainer = new CookieContainer(),
        };

        var client = new HttpClient(handler)
        {
            BaseAddress = new Uri(webApiBaseUrl)
        };

        //设置Cookie
        var cookie = new Cookie("jwt_token", "a.b.c")
        {
            Expires = DateTime.Now.AddDays(7),
            Domain = new Uri(webApiBaseUrl).Host,
            Path = "/",
            Secure = true,           // 仅 HTTPS 传输
            HttpOnly = true,         // 防止 XSS 攻击
        };

        handler.CookieContainer.Add(new Uri(webApiBaseUrl), cookie);

        // 第一次请求,服务端设置 Cookie
        var response = await client.GetAsync("/api/Cookie/GetRequestCookie");
        response.EnsureSuccessStatusCode();

        var content = await response.Content.ReadAsStringAsync();

        Console.WriteLine(content);
    }
}

总结

功能 描述 适用场景
手动设置 Cookie 灵活、简单 单次请求或固定 Cookie
使用 HttpRequestMessage 更精细控制 Cookie 行为 需要合并默认与自定义 Cookie
使用 CookieContainer 自动管理 Cookie 生命周期 多次请求、需要保持会话状态
Cookie 持久化 保存 Cookie 至文件或数据库 程序重启后仍需保持登录状态
跨域 Cookie 手动复制或自定义容器 需要在多个域名之间共享 Cookie
安全 Cookie 设置 SecureHttpOnlySameSite 增强 Cookie 安全性
获取 Cookie 属性 查看 Cookie 的有效期、路径等信息 调试和日志记录
相关推荐
追逐时光者15 小时前
TIOBE 公布 C# 是 2025 年度编程语言
后端·.net
ServBay19 小时前
C# 成为 2025 年的编程语言,7个C#技巧助力开发效率
后端·c#·.net
獨枭21 小时前
.NET Framework 依赖版本冲突解决方案:从现象到本质
.net
云草桑1 天前
.net AI API应用 客户发的信息提取对接上下游系统报价
ai·c#·.net·semantickernel·sk
切糕师学AI1 天前
win下,当.NET控制台进程被强制终止(如关闭控制台、任务管理器结束进程等)时,如何优雅地清理数据
.net·控制台·进程
peixiuhui1 天前
Iotgateway技术手册-3. 架构设计
.net·iot·核心板·iotgateway·开源网关·arm工控板
武藤一雄2 天前
C# 关于多线程如何实现需要注意的问题(持续更新)
windows·后端·microsoft·c#·.net·.netcore·死锁
我是唐青枫2 天前
深入理解 System.Lazy<T>:C#.NET 延迟初始化与线程安全
c#·.net
波波0072 天前
.sln 时代落幕,.slnx成为 .NET 新标准?
.net·vs
mudtools2 天前
基于.NET操作Excel COM组件生成数据透视报表
c#·.net·excel