.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 的有效期、路径等信息 调试和日志记录
相关推荐
fs哆哆11 小时前
在VB.NET中,有没有 ?.这个运算符
java·开发语言·.net
荔园微风17 小时前
微软ML.NET技术详解:从数据科学到生产部署的全栈解决方案
microsoft·.net
荔园微风1 天前
ML.NET机器学习框架基本流程介绍
人工智能·机器学习·.net
InCerry1 天前
为 .NET 10 GC(DATAS)做准备
性能优化·c#·.net·gc
关关长语2 天前
(一) Dotnet使用MCP的Csharp SDK
网络·.net·mcp
喵叔哟2 天前
7. 从0到上线:.NET 8 + ML.NET LTR 智能类目匹配实战--反馈存储与数据治理:MongoDB 设计与运维
运维·mongodb·.net
.NET修仙日记2 天前
SQL Server实战指南:从基础CRUD到高并发处理的完整面试题库
面试·职场和发展·c#·.net·sql server·.net全栈经典面试题库
weixin_456904272 天前
基于.NET Framework 4.0的串口通信
开发语言·c#·.net
yuyuyui3 天前
Roslyn 技术解析:如何利用它做代码规范检查与运行时代码生成?
.net