ZetCode

C# HttpClient

最后修改于 2023 年 7 月 5 日

C# HttpClient 教程展示了如何使用 C# 中的 HttpClient 创建 HTTP 请求。 在示例中,我们创建简单的 GET 和 POST 请求。

超文本传输​​协议 (HTTP) 是一种用于分布式、协作式、超媒体信息系统的应用协议。 HTTP 是万维网数据通信的基础。

HttpClient 是一个基类,用于发送 HTTP 请求并接收来自 URI 标识的资源的 HTTP 响应。

HTTP 请求方法

HTTP 定义了一组请求方法,以指示要对给定资源执行的所需操作。

C# HttpClient 状态码

HTTP 响应状态代码指示特定的 HTTP 请求是否已成功完成。响应分为五个类

Program.cs
namespace HttpClientStatus;

class Program
{
    static async Task Main(string[] args)
    {
        using var client = new HttpClient();

        var result = await client.GetAsync("http://webcode.me");
        Console.WriteLine(result.StatusCode);
    }
}

此示例创建一个 GET 请求到一个小型网站。我们获取请求的状态码。

using var client = new HttpClient();

创建了一个新的 HttpClient

var result = await client.GetAsync("http://webcode.me");

GetAsync 方法将 GET 请求作为异步操作发送到指定的 Uri。 await 运算符暂停封闭 async 方法的评估,直到异步操作完成。 当异步操作完成时,await 运算符返回操作的结果(如果有)。

$ dotnet run
OK

我们得到了 200 OK 状态码;该网站已启动。

C# HttpClient GET 请求

GET 方法请求指定资源的表示。

Program.cs
using var client = new HttpClient();
var content = await client.GetStringAsync("http://webcode.me");

Console.WriteLine(content);

该示例向 webcode.me 网站发出 GET 请求。 它输出主页的简单 HTML 代码。

var content = await client.GetStringAsync("http://webcode.me");

GetStringAsync 向指定的 Uri 发送 GET 请求,并将响应正文作为字符串在异步操作中返回。

$ dotnet run
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="format.css">
    <title>My html page</title>
</head>
<body>

    <p>
        Today is a beautiful day. We go swimming and fishing.
    </p>
    
    <p>
         Hello there. How are you?
    </p>
    
</body>
</html>

C# HttpClient HEAD 请求

HTTP HEAD 方法请求如果使用 HTTP GET 方法请求指定资源会返回的头部信息。

Program.cs
var url = "http://webcode.me";
using var client = new HttpClient();

var result = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, url));

Console.WriteLine(result);

该示例发出 HEAD 请求。

$ dotnet run
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, 
Content: System.Net.Http.HttpConnectionResponseContent, Headers:
{
  Server: nginx/1.6.2
  Date: Tue, 12 Jan 2021 12:01:07 GMT
  Connection: keep-alive
  ETag: "5d32ffc5-15c"
  Accept-Ranges: bytes
  Content-Type: text/html
  Content-Length: 348
  Last-Modified: Sat, 20 Jul 2019 11:49:25 GMT
}

这些是响应的标头字段。

C# HttpClient User-Agent

User-Agent 请求头是一个字符串,它允许服务器和网络对等方识别请求用户代理的应用程序、操作系统、供应商和/或版本。

Program.cs
var url = "http://webcode.me/ua.php";

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("User-Agent", "C# program");

var res = await client.GetStringAsync(url);
Console.WriteLine(res);

该示例为其 GET 请求设置了 User-Agent 标头。 请求的资源只是返回客户端的 User-Agent 字符串。

C# HttpClient HttpRequestMessage

HttpRequestMessage 表示请求消息。

Program.cs
var url = "http://webcode.me";

using var client = new HttpClient();

var msg = new HttpRequestMessage(HttpMethod.Get, url);
msg.Headers.Add("User-Agent", "C# Program");
var res = await client.SendAsync(msg);

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

Console.WriteLine(content);

在此示例中,我们手动构建请求消息。

var msg = new HttpRequestMessage(HttpMethod.Get, url);
msg.Headers.Add("User-Agent", "C# Program");
var res = await client.SendAsync(msg);

使用 HttpRequestMessage 创建 GET 请求消息,并使用 SendAsync 发送。

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

我们使用 ReadAsStringAsync 读取响应的内容。

C# HttpClient 查询字符串

查询字符串是 URL 的一部分,用于将一些数据添加到对资源的请求。 它通常是一系列键/值对。 它跟随路径并以 ? 字符开头。

Program.cs
var u = "http://webcode.me/qs.php";

using var client = new HttpClient();

var builder = new UriBuilder(u);
builder.Query = "name=John Doe&occupation=gardener";
var url = builder.ToString();

var res = await client.GetAsync(url);

var content = await res.Content.ReadAsStringAsync();
Console.WriteLine(content);

查询字符串是使用 UriBuilder 构建的。

$ dotnet run
{"name":"John Doe","occupation":"gardener"}

C# HttpClient 超时

当前,http 请求在 100 秒后超时。 要设置不同的超时,我们可以使用 TimeOut 属性。

using var httpClient = new HttpClient();
httpClient.Timeout = TimeSpan.FromMinutes(3);

在此代码片段中,我们将超时设置为 3 分钟。

C# HttpClient 多个异步请求

在以下示例中,我们生成多个异步 GET 请求。

Program.cs
using System.Text.RegularExpressions;

var urls = new string[] { "http://webcode.me", "http://example.com",
    "http://httpbin.org", "https://ifconfig.me", "http://termbin.com",
    "https://github.com"
};

var rx = new Regex(@"<title>\s*(.+?)\s*</title>",
  RegexOptions.Compiled);

using var client = new HttpClient();

var tasks = new List<Task<string>>();

foreach (var url in urls)
{
    tasks.Add(client.GetStringAsync(url));
}

Task.WaitAll(tasks.ToArray());

var data = new List<string>();

foreach (var task in tasks)
{
    data.Add(await task);
}

foreach (var content in data)
{
    var matches = rx.Matches(content);

    foreach (var match in matches)
    {
        Console.WriteLine(match);
    }
}

我们异步下载给定的网页并打印它们的 HTML 标题标签。

tasks.Add(client.GetStringAsync(url));

GetStringAsync 向指定的 url 发送 GET 请求,并将响应正文作为字符串在异步操作中返回。 它返回一个新任务;在 C# 中,任务表示异步操作。

Task.WaitAll(tasks.ToArray());

Task.WaitAll 等待所有提供的任务完成执行。

data.Add(await task);

await 解包结果值。

$ dotnet run
<title>My html page</title>
<title>Example Domain</title>
<title>httpbin.org</title>
<title>termbin.com - terminal pastebin</title>
<title>GitHub: Where the world builds software · GitHub</title>

C# HttpClient POST 请求

HTTP POST 方法将数据发送到服务器。 请求正文的类型由 Content-Type 标头指示。

$ dotnet add package Newtonsoft.Json

我们需要添加 Newtonsoft.Json 包来处理 JSON 数据。

Program.cs
using System.Text;
using Newtonsoft.Json;

var person = new Person("John Doe", "gardener");

var json = JsonConvert.SerializeObject(person);
var data = new StringContent(json, Encoding.UTF8, "application/json");

var url = "https://httpbin.org/post";
using var client = new HttpClient();

var response = await client.PostAsync(url, data);

var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);

record Person(string Name, string Occupation);

在此示例中,我们将 POST 请求发送到 https://httpbin.org/post 网站,这是一个面向开发人员的在线测试服务。

var person = new Person("John Doe", "gardener");

var json = JsonConvert.SerializeObject(person);
var data = new StringContent(json, Encoding.UTF8, "application/json");

Newtonsoft.Json 包的帮助下,我们将对象转换为 JSON 数据。

var response = await client.PostAsync(url, data);

我们使用 PostAsync 方法发送异步 POST 请求。

var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);

我们读取返回的数据并将其打印到控制台。

$ dotnet run
{
  "args": {}, 
  "data": "{\"Name\":\"John Doe\",\"Occupation\":\"gardener\"}", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Content-Length": "43", 
    "Content-Type": "application/json; charset=utf-8", 
    "Host": "httpbin.org", 
    "X-Amzn-Trace-Id": "Root=1-5ffd917e-349220186065913c2544d3ba"
  }, 
  "json": {
    "Name": "John Doe", 
    "Occupation": "gardener"
  }, 
  ...
  "url": "https://httpbin.org/post"
}

C# HttpClient JSON 请求

JSON(JavaScript 对象表示法)是一种轻量级的数据交换格式。 这种格式易于人类阅读和编写,也易于机器解析和生成。 它是 XML 的一种不太冗长且更具可读性的替代方案。 JSON 的官方 Internet 媒体类型是 application/json

Program.cs
using System.Net.Http.Headers;
using Newtonsoft.Json;

using var client = new HttpClient();

client.BaseAddress = new Uri("https://api.github.com");
client.DefaultRequestHeaders.Add("User-Agent", "C# console program");
client.DefaultRequestHeaders.Accept.Add(
        new MediaTypeWithQualityHeaderValue("application/json"));

var url = "repos/symfony/symfony/contributors";
HttpResponseMessage response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
var resp = await response.Content.ReadAsStringAsync();

List<Contributor> contributors = JsonConvert.DeserializeObject<List<Contributor>>(resp);
contributors.ForEach(Console.WriteLine);

record Contributor(string Login, short Contributions);

此示例生成对 Github 的 GET 请求。 它找出 Symfony 框架的主要贡献者。 它使用 Newtonsoft.Json 来处理 JSON。

client.DefaultRequestHeaders.Add("User-Agent", "C# console program");

在请求标头中,我们指定用户代理。

client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

在 accept 标头值中,我们告知 JSON 是一种可接受的响应类型。

var url = "repos/symfony/symfony/contributors";
HttpResponseMessage response = await client.GetAsync(url);
var resp = await response.Content.ReadAsStringAsync();

我们生成一个请求并异步读取内容。

List<Contributor> contributors = JsonConvert.DeserializeObject<List<Contributor>>(resp);
contributors.ForEach(Console.WriteLine);

我们使用 JsonConvert.DeserializeObject 方法将 JSON 响应转换为 Contributor 对象列表。

C# HttpClient POST 表单数据

POST 请求通常通过 post 表单发送。 请求正文的类型由 Content-Type 标头指示。 FormUrlEncodedContent 是一个容器,用于使用 application/x-www-form-urlencoded MIME 类型编码的名称/值元组。

Program.cs
var url = "https://httpbin.org/post";

using var client = new HttpClient();

var data = new Dictionary<string, string>
{
    {"name", "John Doe"},
    {"occupation", "gardener"}
};

var res = await client.PostAsync(url, new FormUrlEncodedContent(data));

var content = await res.Content.ReadAsStringAsync();
Console.WriteLine(content);

该示例使用 FormUrlEncodedContent 发送表单 POST 请求。

$ dotnet run
{
  "args": {},
  "data": "",
  "files": {},
  "form": {
    "name": "John Doe",
    "occupation": "gardener"
  },
  "headers": {
    "Content-Length": "33",
    "Content-Type": "application/x-www-form-urlencoded",
    "Host": "httpbin.org",
    "X-Amzn-Trace-Id": "Root=1-6218d376-03e6c2f004520f2f2e504f37"
  },
  "json": null,
  ...
  "url": "https://httpbin.org/post"
}

C# HttpClient 代理

代理是请求资源的客户端和提供该资源的服务器之间的中介。

Program.cs
using System.Net;

var port = 7302;
var proxy = "example.com";
var url = "http://webcode.me";

var handler = new HttpClientHandler()
{
    Proxy = new WebProxy(new Uri($"socks5://{proxy}:{port}")),
    UseProxy = true,
};

using var client = new HttpClient(handler);

var res = await client.GetAsync(url);
var content = await res.Content.ReadAsStringAsync();

Console.WriteLine(content);

该示例通过代理创建一个 Web 请求。 C# 使用 WebProxy 设置代理服务器。

C# HttpClient 下载图像

GetByteArrayAsync 向指定的 Uri 发送 GET 请求,并在异步操作中将响应正文作为字节数组返回。

Program.cs
using var httpClient = new HttpClient();

var url = "http://webcode.me/favicon.ico";
byte[] imageBytes = await httpClient.GetByteArrayAsync(url);

string documentsPath = System.Environment.GetFolderPath(
        System.Environment.SpecialFolder.Personal);

string localFilename = "favicon.ico";
string localPath = Path.Combine(documentsPath, localFilename);

Console.WriteLine(localPath);
File.WriteAllBytes(localPath, imageBytes);

在此示例中,我们从 webcode.me 网站下载图像。 该图像被写入用户的 Documents 文件夹。

byte[] imageBytes = await httpClient.GetByteArrayAsync(url);

GetByteArrayAsync 将图像作为字节数组返回。

string documentsPath = System.Environment.GetFolderPath(
    System.Environment.SpecialFolder.Personal);

我们使用 GetFolderPath 方法确定 Documents 文件夹。

File.WriteAllBytes(localPath, imageBytes);

这些字节使用 File.WriteAllBytes 方法写入磁盘。

C# HttpClient 流式传输

流式传输是一种以连续流的形式传输数据的方法,接收计算机可以在整个文件完全发送之前对其进行处理。

Program.cs
using var httpClient = new HttpClient();

var url = "https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.2/images/NetBSD-9.2-amd64-install.img.gz";

var fname = Path.GetFileName(url);

var resp = await httpClient.GetAsync(url, 
    HttpCompletionOption.ResponseHeadersRead);
resp.EnsureSuccessStatusCode();

using Stream ms = await resp.Content.ReadAsStreamAsync();

using FileStream fs = File.Create(fname);
await ms.CopyToAsync(fs);

Console.WriteLine("file downloaded");

在此示例中,我们使用流式传输下载 NetBSD USB 映像。

var resp = await httpClient.GetAsync(url, 
    HttpCompletionOption.ResponseHeadersRead);

使用 HttpCompletionOption.ResponseHeadersRead 选项,异步操作应在响应可用且标头被读取后立即完成。 尚未读取内容。 该方法只会读取标头并将控制权返回。

using Stream ms = await resp.Content.ReadAsStreamAsync();

ReadAsStreamAsync 方法序列化 HTTP 内容并返回一个表示内容作为异步操作的流。

using FileStream fs = File.Create(fname);
await ms.CopyToAsync(fs);

数据不断复制到文件流。

C# HttpClient 基本身份验证

在 HTTP 协议中,基本访问身份验证是一种 HTTP 用户代理(例如 Web 浏览器或控制台应用程序)在发出请求时提供用户名和密码的方法。 在基本 HTTP 身份验证中,请求包含一个标头字段,其格式为 Authorization: Basic <credentials>,其中 credentials 是 id 和密码的 base64 编码,中间用一个冒号 : 连接。

注意:凭据未加密;因此,HTTP 基本身份验证必须与 HTTPS 协议一起使用。

HTTP 基本身份验证是强制执行对 Web 资源访问控制的最简单技术。 它不需要 cookie、会话标识符或登录页面; 相反,HTTP 基本身份验证使用 HTTP 标头中的标准字段。

Program.cs
using System.Text;
using System.Net.Http.Headers;

var userName = "user7";
var passwd = "passwd";
var url = "https://httpbin.org/basic-auth/user7/passwd";

using var client = new HttpClient();

var authToken = Encoding.ASCII.GetBytes($"{userName}:{passwd}");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
        Convert.ToBase64String(authToken));

var result = await client.GetAsync(url);

var content = await result.Content.ReadAsStringAsync();
Console.WriteLine(content);

该示例将凭据发送到 httpbin.org 网站。

var authToken = Encoding.ASCII.GetBytes($"{userName}:{passwd}");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
        Convert.ToBase64String(authToken));

这里我们构建身份验证标头。

var url = "https://httpbin.org/basic-auth/user7/passwd";

URL 包含身份验证详细信息,因为我们使用 httpbin.org 网站对其进行测试。 这样我们就不需要设置自己的服务器。 当然,身份验证详细信息永远不会放入 URL 中。

$ dotnet run
{
    "authenticated": true,
    "user": "user7"
}

来源

HttpClient 类 - 语言参考

在本文中,我们使用 C# HttpClient 创建 HTTP 请求。

作者

我的名字是 Jan Bodnar,我是一位充满激情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 C# 教程