如何通过TCP发送含嵌套列表的对象调用HTTP POST接口?
基于TCP实现HTTP POST请求(无需等待响应)
需求说明
需要通过TCP直接发送HTTP POST请求,核心原因是无需等待服务端响应。目前已实现带参数的TCP GET请求,但需要改为发送包含两个对象列表的JSON请求体,调用HTTP POST接口。示例JSON请求体如下:
{ "CustomerId" : 123, "CalendarYear" : 2023, "ExpensesA": [ {"Id": "1", "Year": "2018", "Losses": "0", "Card": "0", "Taxes": "0"}, {"Id": "2", "Year": "2019", "Losses": "0", "Card": "0", "Taxes": "0"}, {"Id": "3", "Year": "2020", "Losses": "0", "Card": "0", "Taxes": "0"}, {"Id": "4", "Year": "2021", "Losses": "0", "Card": "0", "Taxes": "0"} ], "ExpensesB": [ {"Id": "1", "Year": "2018", "Losses": "0", "Card": "0", "Taxes": "0"}, {"Id": "2", "Year": "2019", "Losses": "0", "Card": "0", "Taxes": "0"}, {"Id": "3", "Year": "2020", "Losses": "0", "Card": "0", "Taxes": "0"}, {"Id": "4", "Year": "2021", "Losses": "0", "Card": "0", "Taxes": "0"} ] }
现有TCP GET请求实现代码(C#):
using var tcp = new TcpClient("localhost", 12345); using var stream = tcp.GetStream(); tcp.SendTimeout = 500; tcp.ReceiveTimeout = 1000; var resourceUri = new StringBuilder($"/Endpoint/{relativeUrl}"); resourceUri.Append($"?id={personId}"); resourceUri.Append($"&year={year}"); var builder = new StringBuilder(); builder.AppendLine($"GET {resourceUri} HTTP/1.1"); builder.AppendLine("Host: host.com"); builder.AppendLine("Connection: close"); builder.AppendLine(); var header = Encoding.ASCII.GetBytes(builder.ToString()); await stream.WriteAsync(header, 0, header.Length);
修改后的TCP POST实现代码
using System.Text; using System.Text.Json; // 定义与JSON结构匹配的实体类 public class ExpenseItem { public string Id { get; set; } public string Year { get; set; } public string Losses { get; set; } public string Card { get; set; } public string Taxes { get; set; } } public class PostRequestData { public int CustomerId { get; set; } public int CalendarYear { get; set; } public List<ExpenseItem> ExpensesA { get; set; } public List<ExpenseItem> ExpensesB { get; set; } } // 发送POST请求的方法 public async Task SendTcpPostRequest(string relativeUrl) { using var tcp = new TcpClient("localhost", 12345); using var stream = tcp.GetStream(); tcp.SendTimeout = 500; // 无需等待响应,将接收超时设为0 tcp.ReceiveTimeout = 0; // 构造请求URL(POST参数一般放在请求体,URL保留固定路径即可) var resourceUri = $"/Endpoint/{relativeUrl}"; // 构造请求体数据 var requestData = new PostRequestData { CustomerId = 123, CalendarYear = 2023, ExpensesA = new List<ExpenseItem> { new ExpenseItem { Id = "1", Year = "2018", Losses = "0", Card = "0", Taxes = "0" }, new ExpenseItem { Id = "2", Year = "2019", Losses = "0", Card = "0", Taxes = "0" }, new ExpenseItem { Id = "3", Year = "2020", Losses = "0", Card = "0", Taxes = "0" }, new ExpenseItem { Id = "4", Year = "2021", Losses = "0", Card = "0", Taxes = "0" } }, ExpensesB = new List<ExpenseItem> { new ExpenseItem { Id = "1", Year = "2018", Losses = "0", Card = "0", Taxes = "0" }, new ExpenseItem { Id = "2", Year = "2019", Losses = "0", Card = "0", Taxes = "0" }, new ExpenseItem { Id = "3", Year = "2020", Losses = "0", Card = "0", Taxes = "0" }, new ExpenseItem { Id = "4", Year = "2021", Losses = "0", Card = "0", Taxes = "0" } } }; // 序列化对象为UTF-8格式的JSON字节数组 var jsonBytes = JsonSerializer.SerializeToUtf8Bytes(requestData); // 构造HTTP请求头 var builder = new StringBuilder(); builder.AppendLine($"POST {resourceUri} HTTP/1.1"); builder.AppendLine("Host: host.com"); builder.AppendLine("Connection: close"); builder.AppendLine("Content-Type: application/json"); builder.AppendLine($"Content-Length: {jsonBytes.Length}"); builder.AppendLine(); // 空行分隔请求头与请求体 // 将请求头转为字节数组 var headerBytes = Encoding.ASCII.GetBytes(builder.ToString()); // 先写入请求头,再写入请求体 await stream.WriteAsync(headerBytes, 0, headerBytes.Length); await stream.WriteAsync(jsonBytes, 0, jsonBytes.Length); // 无需等待响应,写完直接关闭连接 tcp.Close(); }
关键修改点说明
- 请求方法变更:将
GET改为POST,URL不再拼接查询参数(若需保留URL参数可继续添加,但POST数据优先放在请求体)。 - 新增必要HTTP头:添加
Content-Type: application/json告知服务端请求体格式,Content-Length指定请求体字节长度,这是服务端正确解析JSON的核心前提。 - 序列化请求体:通过
System.Text.Json(也可使用Newtonsoft.Json)将实体对象序列化为UTF-8格式的JSON字节数组。 - 调整超时与连接逻辑:因无需等待响应,将
ReceiveTimeout设为0,写完数据后直接关闭TCP连接即可。 - 写入顺序规范:必须先写入HTTP请求头,再写入请求体,两者之间用空行分隔(对应代码中
builder.AppendLine())。
内容的提问来源于stack exchange,提问作者DValdir Martins
相关产品推荐
相关产品推荐

