全部例程

W55MH32作为HTTP客户端

W55MH32

更新于 2026年9月17日

本篇总结

W55MH32 作为 HTTP Client,通过 TCP 连接向 httpbin.org 发送 GET 和 POST 请求并接收响应。

🔑 KEIL MDK、UART调试、硬件TOE引擎、HTTP、DNS、DHCP

硬件平台:本例程基于 W55MH32L-EVB 开发板运行。

采购推荐:点击前往 WIZnet 官方淘宝店铺 选购 W55MH32L-EVB

本示例演示如何在 W55MH32 上实现 HTTP(超文本传输协议)客户端功能,向指定网站(httpbin.org)发送 GET 和 POST 请求并接收响应。实现步骤:DNS 解析域名获取 IP → 按 HTTP 协议规范组包(GET/POST Header)→ 发送请求并监听响应(含超时与异常处理)。

前置工具准备

开始本例程前,请确认以下工具已安装:

网络要求

因为本示例需要访问互联网,请确保 W55MH32 的网络环境及配置能够正常访问互联网(路由器需连接外网)。

HTTP 协议简介

HTTP(HyperText Transfer Protocol)是一种用于分布式、协作式、超媒体信息系统的应用层协议,基于 TCP/IP 通信协议来传递数据,是万维网数据通信的基础。它采用请求-响应模型:客户端发起请求,服务器处理后返回响应;本身无状态,每次请求独立。

HTTP 常用的请求方法有 GET 和 POST:

方法参数位置数据大小安全性典型用途
GETURL 查询字符串受 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 服务器可用。

  1. Micro USB 线连接 DEBUG USB 口到 PC(供电 + 调试串口)
  2. 网线连接开发板 RJ45 网口 到路由器 LAN 口(路由器需连外网)
┌───────────┐
│ W55MH32 │
│ (HTTP │
│ Client) │
└─────┬─────┘
│ 网线
┌─────┴─────┐
│ 路由器 │
│192.168.1.1│
└─────┬─────┘
│ Internet
┌─────┴─────┐
│httpbin.org│
│ (HTTP │
│ Server) │
└───────────┘
↑
DEBUG USB ──→ WIZ UartTool
网络拓扑:W55MH32 作为 HTTP Client,通过路由器访问互联网上的 httpbin.org

工程结构

工程位于 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 服务器返回了响应报文。请求和响应原文都通过串口打印出来:

HTTP GET 请求 httpbin.org/get?username=admin&password=admin — 服务器返回 JSON 响应

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

HTTP POST 请求 httpbin.org/post(表单数据 username=admin&password=admin)— 服务器返回 JSON 回显


常见问题

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 状态处理异常响应

下载本章例程

我们提供完整的工程文件以及配套开发板,方便你随时测试,快速完成产品开发:

开发环境: Keil MDK5 配套开发板

Andy

W5500 技术支持专家