简单的 HTTP 服务器
现在让我们把开发板变成一个微型网络服务器,在收到 GET
请求后,它会提供来自内部温度传感器的数据。
配置
intro/http-server/
中有已准备好的项目框架。它会建立 Wi-Fi 连接,但你需要将其配置为使用 cfg.toml
中的网络凭据。
intro/http-server/examples/https-server.rs
包含一个解答。你可以用下面的命令运行它:
cargo run --example http_server
处理请求
为了用浏览器访问开发板,你需要知道板子的 IP 地址。
✅ 运行 intro/http-server
中的框架代码。输出应该包含板子的 IP 地址,类似这样:
I (3862) esp_netif_handlers: sta ip: 192.168.178.54, mask: ...
...
Server awaiting connection
sta ip
指的是 Wi-Fi 术语站点(station),代表连接到接入点(access point)的接口。这就是你需要输入浏览器的地址(或其他 HTTP 客户端,如 curl
)。
🔎 ESP-IDF 会尝试在本地网络中注册主机名
espressif
,因此使用http://espressif/
代替http://<sta ip>/
通常也可以。你可以通过设置
sdkconfig.defaults
中的CONFIG_LWIP_LOCAL_HOSTNAME
来更改主机名,例如CONFIG_LWIP_LOCAL_HOSTNAME="esp32c3"
。
向客户端发送 HTTP 数据包括:
- 创建一个
EspHttpServer
实例 - 在主函数中循环,这样它就不会终止——终止会导致服务器离开作用域然后关闭
- 为需要提供内容的每个路径设置单独的请求处理(
handler
)函数。任何未配置的路径都会产生404
错误。这些处理函数以 Rust 闭包的形式内联实现,如下所示:
#![allow(unused)] fn main() { server.fn_handler(path, Method::Get, |request| { // ... // 构造一个响应 let mut response = request.into_ok_response()?; // 写入期望的数据 response.write_all(&some_buf)?; // 如果完成了处理,处理函数期望一个 `Completion` 作为结果 // 这是通过它实现的: Ok(()) }); }
✅ 使用默认的 esp_idf_svc::http::server::Configuration
创建一个 EspHttpServer
实例。默认配置将使它自动监听 80 端口。
✅ 验证与 http://<sta ip>/
的连接是否会产生 404
(not found)错误,表明 This URI does not exist
。
✅ 为根路径("/"
)编写请求处理函数。处理函数会在 http://<sta ip>/
上发送问候消息,使用已提供的 index_html()
函数来生成 HTML 字符串。
动态数据
我们还可以向客户端发送动态信息。该框架包含一个已配置好的 temp_sensor
,用于测量开发板的内部温度。
✅ 在 http://<sta ip>/temperature
上编写第二个请求处理函数,用于报告芯片的温度。使用已提供的 temperature(val: f32)
函数来生成 HTML 字符串。
💡 如果要发送响应字符串,需要通过 a_string.as_bytes()
将其转换为 &[u8]
slice。
💡 温度传感器需要独占(可变)访问。将它作为有所有权的值传递给请求处理函数是行不通的(因为它会在第一次调用后被丢弃)——你可以通过把处理函数变成 move ||
闭包来解决这个问题。将传感器包裹在 Arc<Mutex<_>>
中,将此 Arc
的一个 clone()
保留在主函数中,并将另一个移动到闭包中。
Troubleshooting
httpd_txrx: httpd_resp_send_err
可以通过重启解决。如果不起作用,可以使用cargo clean
。- 确保你的电脑和开发板使用的是相同的 Wi-Fi 网络。