网络请求
开发专题 · HttpClient / WebRequest / Socket(.NET Framework 4.8)
本页说明在 .NET Framework 4.8 窗体(或控制台)项目中发起 HTTP GET/POST,以及用 Socket 做最简 TCP 收发。目标框架以 LCode 默认的 .NET 4.8 为准;示例写法面向 C# 5.0 与 VB.NET(可用 async/Await,勿用 C# 6+ 语法如字符串插值、nameof)。操作文案以 LCode 中文界面为准。异步与 UI 线程的通用说明见 异步、同步与多线程;解析响应体见 JSON 与 XML 解析。
选用哪种 API
| API | 命名空间 / 程序集 | 适用 |
|---|---|---|
HttpClient |
System.Net.Http(程序集 System.Net.Http) |
现代 HTTP 客户端;推荐新代码优先用。异步方法齐全;同步需自行等待任务完成 |
WebRequest / HttpWebRequest + WebResponse |
System.Net(框架自带) |
经典 HTTP;同步 GetResponse 直观。新项目仍可用,但微软更鼓励 HttpClient |
Socket |
System.Net.Sockets |
裸 TCP/UDP;自定协议、设备通讯、非 HTTP。需自己拼字节与粘包处理 |
在 LCode 中添加引用
- 窗体项目默认已有
System、System.Core等;WebRequest/Socket一般无需额外浏览引用。 - 使用
HttpClient时:项目 → 添加引用 → .NET集合浏览器,勾选System.Net.Http→ 确定。若列表中无该项,用浏览指向本机 .NET 4.8 参考程序集中的System.Net.Http.dll。 - 确认引用属性中本地复制按需要设置(框架程序集通常 False 即可)。
- 菜单 编译 → 编译解决方案(F8),确认无「找不到类型或命名空间 System.Net.Http」。
同步与异步(窗体注意)
网络 IO 可能耗时数秒。在按钮点击等 UI 事件里同步阻塞会导致窗体假死;优先用异步事件处理(C# async void 事件 / VB Async Sub),或把阻塞调用放到后台线程。详解见异步专页。
| 方式 | 做法 | 注意 |
|---|---|---|
| 异步(推荐 UI) | await client.GetStringAsync(...) / Await;或 BeginGetResponse 回调 |
事件处理可用 async void / Async Sub;库方法优先返回 Task |
| 同步 | HttpWebRequest.GetResponse();或对 HttpClient 任务调用 .Result / GetAwaiter().GetResult() |
勿在 UI 线程长时间阻塞。WinForms 上对未 ConfigureAwait(false) 的任务滥用 .Result 可能死锁 |
HttpClient:GET
建议在窗体生命周期内复用同一个 HttpClient 实例(勿每个请求 new 后立刻 Dispose 成习惯;短示例可用局部变量)。下面用异步按钮点击拉取文本。
using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows.Forms;
// 窗体字段,复用
private static readonly HttpClient http = new HttpClient();
private async void btnGet_Click(object sender, EventArgs e)
{
try
{
string url = "https://httpbin.org/get";
string body = await http.GetStringAsync(url);
txtResult.Text = body;
}
catch (HttpRequestException ex)
{
MessageBox.Show("请求失败: " + ex.Message);
}
catch (TaskCanceledException)
{
MessageBox.Show("请求超时或已取消。");
}
}
Imports System.Net.Http
Imports System.Threading.Tasks
Imports System.Windows.Forms
' 窗体字段,复用
Private Shared ReadOnly http As New HttpClient()
Private Async Sub btnGet_Click(sender As Object, e As EventArgs) Handles btnGet.Click
Try
Dim url As String = "https://httpbin.org/get"
Dim body As String = Await http.GetStringAsync(url)
txtResult.Text = body
Catch ex As HttpRequestException
MessageBox.Show("请求失败: " & ex.Message)
Catch ex As TaskCanceledException
MessageBox.Show("请求超时或已取消。")
End Try
End Sub
HttpClient,可写 http.GetStringAsync(url).GetAwaiter().GetResult()(VB:.GetAwaiter().GetResult()),并尽量在非 UI 线程执行。设置超时:http.Timeout = TimeSpan.FromSeconds(30)。
HttpClient:POST
用 StringContent 发送 JSON 或表单文本;按需设置 Content-Type。
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
private async void btnPost_Click(object sender, EventArgs e)
{
string url = "https://httpbin.org/post";
string json = "{\"name\":\"demo\",\"qty\":1}";
using (StringContent content = new StringContent(json, Encoding.UTF8, "application/json"))
{
HttpResponseMessage resp = await http.PostAsync(url, content);
string body = await resp.Content.ReadAsStringAsync();
// 也可先检查 resp.IsSuccessStatusCode / (int)resp.StatusCode
txtResult.Text = body;
}
}
Imports System.Net.Http
Imports System.Text
Private Async Sub btnPost_Click(sender As Object, e As EventArgs) Handles btnPost.Click
Dim url As String = "https://httpbin.org/post"
Dim json As String = "{""name"":""demo"",""qty"":1}"
Using content As New StringContent(json, Encoding.UTF8, "application/json")
Dim resp As HttpResponseMessage = Await http.PostAsync(url, content)
Dim body As String = Await resp.Content.ReadAsStringAsync()
' 也可先检查 resp.IsSuccessStatusCode / CInt(resp.StatusCode)
txtResult.Text = body
End Using
End Sub
HttpClient 常用成员
| 成员 | 类型 | 说明 |
|---|---|---|
Timeout |
属性 | 整次请求超时;默认约 100 秒 |
DefaultRequestHeaders |
属性 | 默认请求头(如 User-Agent、Accept) |
BaseAddress |
属性 | 相对 URL 的基址 |
GetAsync / GetStringAsync |
方法 | GET;后者直接读字符串正文 |
PostAsync / PutAsync / DeleteAsync |
方法 | 对应 HTTP 动词;正文放在 HttpContent |
SendAsync |
方法 | 自定义 HttpRequestMessage(方法、头、内容) |
WebRequest / WebResponse:GET
HttpWebRequest 由 WebRequest.Create 得到。同步路径用 GetResponse;异步可用 BeginGetResponse/EndGetResponse,或包装为 Task(.NET 4.5+ 有 GetResponseAsync)。
using System.IO;
using System.Net;
using System.Text;
string url = "https://httpbin.org/get";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = "GET";
req.Timeout = 30000; // 毫秒
req.UserAgent = "LCode-Sample/1.0";
using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse())
using (Stream stream = resp.GetResponseStream())
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
{
string body = reader.ReadToEnd();
// resp.StatusCode、resp.ContentType
Console.WriteLine(body);
}
Imports System.IO
Imports System.Net
Imports System.Text
Dim url As String = "https://httpbin.org/get"
Dim req As HttpWebRequest = CType(WebRequest.Create(url), HttpWebRequest)
req.Method = "GET"
req.Timeout = 30000 ' 毫秒
req.UserAgent = "LCode-Sample/1.0"
Using resp As HttpWebResponse = CType(req.GetResponse(), HttpWebResponse)
Using stream As Stream = resp.GetResponseStream()
Using reader As New StreamReader(stream, Encoding.UTF8)
Dim body As String = reader.ReadToEnd()
' resp.StatusCode、resp.ContentType
Console.WriteLine(body)
End Using
End Using
End Using
WebRequest / WebResponse:POST
设置 Method = "POST",写入请求流,再读响应。下面发送 application/x-www-form-urlencoded 表单;JSON 则改 ContentType 与正文即可。
using System.IO;
using System.Net;
using System.Text;
string url = "https://httpbin.org/post";
byte[] data = Encoding.UTF8.GetBytes("name=demo&qty=1");
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = data.Length;
req.Timeout = 30000;
using (Stream reqStream = req.GetRequestStream())
{
reqStream.Write(data, 0, data.Length);
}
using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse())
using (Stream stream = resp.GetResponseStream())
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
{
string body = reader.ReadToEnd();
Console.WriteLine(body);
}
Imports System.IO
Imports System.Net
Imports System.Text
Dim url As String = "https://httpbin.org/post"
Dim data As Byte() = Encoding.UTF8.GetBytes("name=demo&qty=1")
Dim req As HttpWebRequest = CType(WebRequest.Create(url), HttpWebRequest)
req.Method = "POST"
req.ContentType = "application/x-www-form-urlencoded"
req.ContentLength = data.Length
req.Timeout = 30000
Using reqStream As Stream = req.GetRequestStream()
reqStream.Write(data, 0, data.Length)
End Using
Using resp As HttpWebResponse = CType(req.GetResponse(), HttpWebResponse)
Using stream As Stream = resp.GetResponseStream()
Using reader As New StreamReader(stream, Encoding.UTF8)
Dim body As String = reader.ReadToEnd()
Console.WriteLine(body)
End Using
End Using
End Using
HttpWebRequest / HttpWebResponse 常用成员
| 成员 | 类型 | 说明 |
|---|---|---|
Method |
属性 | GET / POST / PUT 等 |
ContentType / ContentLength |
属性 | 请求体类型与长度(POST 时常需设置) |
Timeout / ReadWriteTimeout |
属性 | 超时(毫秒) |
Headers / UserAgent |
属性 | 自定义头;部分头有专用属性 |
GetRequestStream |
方法 | 写入 POST 正文(同步) |
GetResponse / GetResponseAsync |
方法 | 发送并取得 HttpWebResponse |
StatusCode / GetResponseStream |
响应 | 状态码与响应正文流 |
ServicePointManager.SecurityProtocol(勿随意全局降级到过时协议)。本页不展开证书绕过——生产环境应修证书链,而不是忽略校验。
Socket:最简 TCP 客户端
当对方不是 HTTP,而是设备或自定文本协议时,用 Socket(或更高层的 TcpClient)。下面连接主机端口、发送一行 UTF-8 文本并尝试读回;真实协议请按文档组帧。
using System;
using System.Net.Sockets;
using System.Text;
string host = "127.0.0.1";
int port = 9000;
using (Socket socket = new Socket(
AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
socket.ReceiveTimeout = 5000;
socket.SendTimeout = 5000;
socket.Connect(host, port);
byte[] sendBuf = Encoding.UTF8.GetBytes("PING\n");
socket.Send(sendBuf);
byte[] recvBuf = new byte[1024];
int n = socket.Receive(recvBuf);
string reply = Encoding.UTF8.GetString(recvBuf, 0, n);
Console.WriteLine(reply);
socket.Shutdown(SocketShutdown.Both);
}
Imports System.Net.Sockets
Imports System.Text
Dim host As String = "127.0.0.1"
Dim port As Integer = 9000
Using socket As New Socket(
AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
socket.ReceiveTimeout = 5000
socket.SendTimeout = 5000
socket.Connect(host, port)
Dim sendBuf As Byte() = Encoding.UTF8.GetBytes("PING" & vbLf)
socket.Send(sendBuf)
Dim recvBuf(1023) As Byte
Dim n As Integer = socket.Receive(recvBuf)
Dim reply As String = Encoding.UTF8.GetString(recvBuf, 0, n)
Console.WriteLine(reply)
socket.Shutdown(SocketShutdown.Both)
End Using
Socket 常用成员
| 成员 | 类型 | 说明 |
|---|---|---|
Connect / ConnectAsync |
方法 | 连接到远程终结点 |
Send / Receive |
方法 | 发送 / 接收字节;一次未必收完整条消息 |
SendTimeout / ReceiveTimeout |
属性 | 超时(毫秒) |
Shutdown / Close |
方法 | 优雅关闭与释放 |
Connected |
属性 | 上次操作后的连接状态提示(非实时心跳) |
注意事项
| 主题 | 说明 |
|---|---|
| UI 线程 | 窗体事件里优先异步;同步网络调用会卡住界面刷新与点击。 |
| HttpClient 生命周期 | 长期复用同一实例;频繁创建/释放可能导致套接字耗尽。 |
| 异常 | HTTP 层常见 HttpRequestException、WebException;超时可能表现为取消或 WebExceptionStatus.Timeout。 |
| 编码 | 读写正文时明确 UTF-8(或对方约定编码),避免中文乱码。 |
| 防火墙 / 代理 | 目标机须能出网或访问内网服务;企业代理时可能要配置 WebRequest.DefaultWebProxy 或系统代理。 |
| C# 语言版本 | LCode / .NET 4.8 场景按 C# 5.0 写:可用 async/await,勿用 $"…"、nameof、?. 等。 |
相关阅读
- 异步、同步与多线程 — async/await、线程与 UI
- JSON 与 XML 解析 — 解析 HTTP 响应正文
- 引用 DLL — 添加
System.Net.Http等程序集 - 运行与编译 — 运行与输出目录