W55MH32作为HTTP客户端
更新于 2026年9月17日
本篇总结
W55MH32 作为 HTTP Client,通过 TCP 连接向 httpbin.org 发送 GET 和 POST 请求并接收响应。
硬件平台:本例程基于 W55MH32L-EVB 开发板运行。
采购推荐:点击前往 WIZnet 官方淘宝店铺 选购 W55MH32L-EVB
本示例演示如何在 W55MH32 上实现 HTTP(超文本传输协议)客户端功能,向指定网站(httpbin.org)发送 GET 和 POST 请求并接收响应。实现步骤:DNS 解析域名获取 IP → 按 HTTP 协议规范组包(GET/POST Header)→ 发送请求并监听响应(含超时与异常处理)。
前置工具准备
开始本例程前,请确认以下工具已安装:
- WIZ UartTool V1.0:串口调试工具:点击下载
网络要求
因为本示例需要访问互联网,请确保 W55MH32 的网络环境及配置能够正常访问互联网(路由器需连接外网)。
HTTP 协议简介
HTTP(HyperText Transfer Protocol)是一种用于分布式、协作式、超媒体信息系统的应用层协议,基于 TCP/IP 通信协议来传递数据,是万维网数据通信的基础。它采用请求-响应模型:客户端发起请求,服务器处理后返回响应;本身无状态,每次请求独立。
HTTP 常用的请求方法有 GET 和 POST:
| 方法 | 参数位置 | 数据大小 | 安全性 | 典型用途 |
|---|---|---|---|---|
| GET | URL 查询字符串 | 受 URL 长度限制 | 明文显示,较低 | 获取资源 |
| POST | 请求体 | 无明显限制 | 相对安全 | 提交数据 |
GET 请求格式如下:
GET <Request-URI> HTTP/<Version>
<Headers>
<Blank Line>POST 请求格式如下(多了一个 Body):
POST <Request-URI> HTTP/<Version>
<Headers>
<Blank Line>
<Body>HTTP 响应由状态行、响应头和响应体三部分组成。状态码分五类:1xx 信息性、2xx 成功、3xx 重定向、4xx 客户端错误、5xx 服务器错误。下面是使用 httpbin.org 测试的 GET 和 POST 请求与响应实例:
GET 请求示例
//请求
GET /get?username=admin&password=admin HTTP/1.1
Host:httpbin.org
//响应
HTTP/1.1 200 OK
Date: Tue, 10 Dec 2024 10:41:13 GMT
Content-Type: application/json
Content-Length: 278
Connection: keep-alive
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
{
"args": {
"password": "admin",
"username": "admin"
},
"headers": {
"Host": "httpbin.org",
"X-Amzn-Trace-Id": "Root=1-67581ac9-236349c67cb21dcc24c54215"
},
"origin": "118.99.2.9",
"url": "http://httpbin.org/get?username=admin&password=admin"
}POST 请求示例
//请求
POST /post HTTP/1.1
Host:httpbin.org
Content-Type:application/x-www-form-urlencoded
Content-Length:29
username=admin&password=admin
//响应
HTTP/1.1 200 OK
Date: Tue, 10 Dec 2024 10:44:52 GMT
Content-Type: application/json
Content-Length: 374
Connection: keep-alive
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
{
"args": {},
"data": "username=admin&password=admin",
"files": {},
"form": {},
"headers": {
"Content-Length": "29",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"X-Amzn-Trace-Id": "Root=1-67581ba4-744fdecf1da1bcf3180f9fa3"
},
"json": null,
"origin": "118.99.2.9",
"url": "http://httpbin.org/post"
}httpbin.org 测试工具
httpbin.org 是一个专门测试 HTTP 协议的网站。向 httpbin.org/get 发送 GET 请求,它会将提交的参数回显在 JSON 响应中;向 httpbin.org/post 发送 POST 请求,它同样会回显请求体内容。非常适合验证 HTTP Client 的实现是否正确。
硬件连接与拓扑
请注意:
开发板需通过路由器接入互联网,路由器需能正常访问外网。本例程会访问 httpbin.org,请确保 DNS 服务器可用。
- Micro USB 线连接 DEBUG USB 口到 PC(供电 + 调试串口)
- 网线连接开发板 RJ45 网口 到路由器 LAN 口(路由器需连外网)
│ W55MH32 │
│ (HTTP │
│ Client) │
└─────┬─────┘
│ 网线
┌─────┴─────┐
│ 路由器 │
│192.168.1.1│
└─────┬─────┘
│ Internet
┌─────┴─────┐
│httpbin.org│
│ (HTTP │
│ Server) │
└───────────┘
↑
DEBUG USB ──→ WIZ UartTool
工程结构
工程位于 SDK 内 1.SDK\ModuleDemo\WZTOE\4.HTTPClient\,核心文件如下:
4.HTTPClient/
├── Project/
│ └── Project.uvprojx ← Keil 工程文件
└── USER/
├── main.c ← 硬件初始化 + 网络配置 + DNS解析 + HTTP请求
├── wiz_interface/
│ ├── wiz_interface.c ← PHY 检测 / 网络信息打印
│ └── wiz_interface.h
├── httpClient/
│ ├── httpClient.c ← HTTP 请求组包 + 发送/接收状态机
│ └── httpClient.h
├── dns/
│ ├── dns.c ← DNS 域名解析
│ └── dns.h
├── uart/
│ ├── bsp_uart.c ← 调试串口 + printf 重定向
│ └── bsp_uart.h
├── tim/
│ └── bsp_tim.c/h ← TIM3 1ms 定时器(供 DHCP/DNS 超时)
└── delay/
└── delay.c/h ← SysTick 毫秒延时
本例程相比 DHCP 章节的核心新增:DNS 域名解析、HTTP 请求组包(GET/POST)、TCP Client 状态机发送请求并接收响应。
步骤1:通过 DNS 解析 HTTP 服务器域名
文件:USER/main.c — 建立 TCP 连接需要目标 IP 地址,而 httpbin.org 是域名。通过 do_dns() 借助 DNS 协议解析域名,获取 httpbin.org 的 IP 地址。
if (do_dns(ethernet_buf, org_server_name, org_server_ip))
{
printf("DNS request failed.\r\n");
while (1)
{
}
}
do_dns() 接收域名 org_server_name,解析成功后将 IP 写入 org_server_ip。失败则死循环。
步骤2:HTTP GET 和 POST 请求组包
文件:USER/httpClient/httpClient.c — 按 HTTP 协议规范组包。定义两个函数分别生成 GET 和 POST 请求报文。
/**
* @brief HTTP GET : Request package combination package.
* @param pkt: Array cache for grouping packages
* @return pkt: Package length
*/
uint32_t http_get_pkt(uint8_t *pkt)
{
*pkt = 0;
// request type URL HTTP protocol version
strcat((char *)pkt, "GET /get?username=admin&password=admin HTTP/1.1\r\n");
// Host address, which can be a domain name or a specific IP address.
strcat((char *)pkt, "Host: httpbin.org\r\n");
// end
strcat((char *)pkt, "\r\n");
return strlen((char *)pkt);
}
/**
* @brief HTTP POST : Request package combination package.
* @param pkt: Array cache for grouping packages
* @return pkt: Package length
*/
uint32_t http_post_pkt(uint8_t *pkt)
{
*pkt = 0;
// request type URL HTTP protocol version
strcat((char *)pkt, "POST /post HTTP/1.1\r\n");
// Host address, which can be a domain name or a specific IP address.
strcat((char *)pkt, "Host: httpbin.org\r\n");
// Main content format
strcat((char *)pkt, "Content-Type:application/x-www-form-urlencoded\r\n");
// Main content lenght
strcat((char *)pkt, "Content-Length:29\r\n");
// separator
strcat((char *)pkt, "\r\n");
// main content
strcat((char *)pkt, "username=admin&password=admin");
return strlen((char *)pkt);
}http_get_pkt() 组包的内容:
GET /get?username=admin&password=admin HTTP/1.1
Host: httpbin.org
http_post_pkt() 组包的内容:
POST /post HTTP/1.1
Host: httpbin.org
Content-Type:application/x-www-form-urlencoded
Content-Length:29
username=admin&password=admin
组包要点
GET 请求只需请求行 + Host 头 + 空行;POST 请求还需 Content-Type、Content-Length 头和请求体。每行以 \r\n 结尾,头与体之间用空行 \r\n 分隔。
步骤3:发送 HTTP 请求并处理响应
文件:USER/main.c — 组包完成后调用 do_http_request() 发送请求。先发送 GET 请求,再发送 POST 请求。
len = http_get_pkt(ethernet_buf);
do_http_request(SOCKET_ID, ethernet_buf, len, org_server_ip, org_port);
// Send a POST request.
len = http_post_pkt(ethernet_buf);
do_http_request(SOCKET_ID, ethernet_buf, len, org_server_ip, org_port);
do_http_request() 函数运行一个 TCP Client 状态机,负责发送请求并监听响应,具体内容如下:
/**
* @brief HTTP Client get data stream test.
* @param sn: socket number
* @param buf: request message content
* @param len request message length
* @param destip: destion ip
* @param destport: destion port
* @return 0:timeout,1:Received response.
*/
uint8_t do_http_request(uint8_t sn, uint8_t *buf, uint16_t len, uint8_t *destip, uint16_t destport)
{
uint16_t local_port = 50000;
uint16_t recv_timeout = 0;
uint8_t send_flag = 0;
while (1)
{
switch (getSn_SR(sn))
{
case SOCK_INIT:
// Connect to http server.
connect(sn, destip, destport);
break;
case SOCK_ESTABLISHED:
if (send_flag == 0)
{
// send request
send(sn, buf, len);
send_flag = 1;
printf("send request:\r\n");
for (uint16_t i = 0; i < len; i++)
{
printf("%c", *(buf + i));
}
printf("\r\n");
}
// Response content processing
len = getSn_RX_RSR(sn);
if (len > 0)
{
printf("Receive response:\r\n");
while (len > 0)
{
len = recv(sn, buf, len);
for (uint16_t i = 0; i < len; i++)
{
printf("%c", *(buf + i));
}
len = getSn_RX_RSR(sn);
}
printf("\r\n");
disconnect(sn);
close(sn);
return 1;
}
else
{
recv_timeout++;
delay_ms(1000);
}
// timeout handling
if (recv_timeout > 10)
{
printf("request fail!\r\n");
disconnect(sn);
close(sn);
return 0;
}
break;
case SOCK_CLOSE_WAIT:
// If there is a request error, the server will immediately send a close request,
// so the error response content needs to be processed here.
len = getSn_RX_RSR(sn);
if (len > 0)
{
printf("Receive response:\r\n");
while (len > 0)
{
len = recv(sn, buf, len);
for (uint16_t i = 0; i < len; i++)
{
printf("%c", *(buf + i));
}
len = getSn_RX_RSR(sn);
}
printf("\r\n");
disconnect(sn);
close(sn);
return 1;
}
close(sn);
break;
case SOCK_CLOSED:
// close socket
close(sn);
// open socket
socket(sn, Sn_MR_TCP, local_port, 0x00);
break;
default:
break;
}
}
}状态机说明
- SOCK_CLOSED → 打开 TCP Socket
- SOCK_INIT → 连接 httpbin.org:80
- SOCK_ESTABLISHED → 发送请求,监听响应,10 秒超时
- SOCK_CLOSE_WAIT → 处理服务器异常响应后关闭
异常处理
如果服务器返回异常响应,会立即关闭 TCP 连接,Socket 进入 SOCK_CLOSE_WAIT。在此分支中先检查是否有接收数据,如有则读取并打印响应内容,确保异常响应不被丢失。
运行验证
烧录例程运行后,首先打印 PHY 链路检测和 DHCP 获取网络信息,然后是 DNS 解析 httpbin.org 域名结果。打开 WIZ UartTool V1.0,连接 DEBUG USB 对应 COM 口(115200 / 8N1),预期串口输出如下:
W55MH32 HTTP Client example
PHY link
The current Mbtis speed : 100Mbps
The current Duplex Mode : Full-Duplex
DHCP running
DHCP success!
====================================================================================================
W55MH32 network configuration : DHCP
MAC : 00:08:DC:00:0E:9A
IP : 192.168.1.6
Subnet Mask : 255.255.255.0
Gateway : 192.168.1.1
DNS : 192.168.1.1
====================================================================================================
> Translated httpbin.org to 34.198.63.32
send request:
GET /get?username=admin&password=admin HTTP/1.1
Host: httpbin.org
Receive response:
HTTP/1.1 200 OK
....
请注意
因为本示例需要访问互联网,请确保 W55MH32 的网络环境及配置能够正常访问互联网。
接着发送了一次 GET 请求报文,HTTP 服务器返回了响应报文。请求和响应原文都通过串口打印出来:

最后发送了一次 POST 请求报文,HTTP 服务器返回了响应报文:

常见问题
Q: GET 和 POST 请求有什么区别
GET 方法通过 URL 查询字符串传递参数,数据在 URL 中明文显示,长度受 URL 限制,适合获取资源。POST 方法将数据放在请求体中,可传递大量数据,相对更安全,适合提交数据。在 W55MH32 实现中,GET 组包只需请求行和 Host 头,POST 组包还需包含 Content-Type、Content-Length 和请求体。
Q: 为什么需要先进行 DNS 解析
HTTP 基于 TCP 协议,建立 TCP 连接需要目标服务器的 IP 地址。而 httpbin.org 是域名,无法直接用于 TCP 连接。因此必须先通过 DNS 协议将域名解析为 IP 地址,再使用该 IP 地址建立 TCP 连接并发送 HTTP 请求。
Q: 如何处理 HTTP 服务器异常响应
如果服务器返回异常响应,会立即关闭 TCP 连接,此时 Socket 状态会进入 SOCK_CLOSE_WAIT。在 do_http_request() 函数的 SOCK_CLOSE_WAIT 分支中,会先检查是否有接收数据,如有则读取并打印响应内容,然后关闭 Socket。这样可以确保异常响应内容不会被丢失。
Q: HTTP 请求超时如何处理
在 SOCK_ESTABLISHED 状态下,如果发送请求后未收到响应,程序会每秒递增 recv_timeout 计数器。当 recv_timeout 超过 10(即等待超过 10 秒)时,判定为请求失败,打印 "request fail!" 并断开连接、关闭 Socket,返回 0 表示超时。
总结
- HTTP 协议基础:HTTP 是基于 TCP/IP 的应用层协议,采用请求-响应模型,具有无状态、无连接的特点
- 两种请求方法:GET 通过 URL 传递参数获取资源,POST 通过请求体提交数据
- 响应三部分:状态行(含状态码)、响应头(含 Content-Type 等)、响应体(实际数据)
- 实现步骤:DNS 解析域名获取 IP → 按 HTTP 规范组包 → 发送请求并监听响应
- 超时与异常处理:10 秒超时机制 + SOCK_CLOSE_WAIT 状态处理异常响应