httpd

YIN 发布于 2025-05-18 116 次阅读


  • esp_http_server.h
  • esp_log.h

初始化

前提:网络相关配置已经完成

  • 获取httpd默认配置  httpd_config_t Config = HTTPD_DEFAULT_CONFIG()
  • 创建http服务器句柄 static httpd_handle_t Server
  • 启动服务器 httpd_start()
  • 注册一个或多个url回调 httpd_register_uri_handler()

示例:
获取默认配置 -> 获取http服务器句柄 -> 启动服务器 -> 注册回调

static httpd_handle_t Server = NULL;

void httpServerStart()
{
  if (Server == NULL) return;
  httpd_config_t Config = HTTPD_DEFAULT_CONFIG();
  /* 启动HTTP服务器 */
  if (httpd_start(&Server, &Config) == ESP_OK) {
    /* 在这里注册你的回调 */
    httpd_register_uri_handler(Server, &<你的回调句柄>);
  }
}

回调示例:

/* 接收 */
esp_err_t httpPostHandler(httpd_req_t *r)
{
    /* 实现你的程序 */
    //httpd_resp_send(r, SendData, HTTPD_RESP_USE_STRLEN);
    return ESP_OK;
}

/* 传输网页 */
esp_err_t httpGetHandler(httpd_req_t *r)
{
    /* 实现你的程序 */
    //httpd_resp_send(r, SendData, HTTPD_RESP_USE_STRLEN);
    return ESP_OK;
}

/* post请求 */
httpd_uri_t UriPost = {
    .uri = "/text",               //按照实际情况更改
    .method = HTTP_POST,
    .handler = httpPostHandler,
    .user_ctx = NULL
};

/* get请求 get网页 */
httpd_uri_t UriGet = {
    .uri = "/",                   
    .method = HTTP_GET,
    .handler = httpGetHandler,
    .user_ctx = NULL
};

关闭

esp_err_t httpd_stop(httpd_handle_t handle)

传输技巧

部分存储在片内rom或者外置存储器的内容可能过于庞大,较难在一次传输内完成(这种数据通常需要先经手内存,此时就可能出现内存不足)
一种解决方案:分成多个区块完成

示例:

const char* WebDataUrl = "/spiflash/web.txt"; //储存在片内rom的比较庞大的数据

void httpSendChunk(httpd_req_t *r)
{
    /* 常规的读取方式 */
    FILE *File = fopen(WebDataUrl,"rb");
    if (File == NULL) {
        ESP_LOGE(__func__,"Failed to open file");
        return;
    }
    uint8_t Buffer[384];    //使用分块传输可以使用很小的Buffer
    int32_t ReadBytes = 0;  //获取fread成功读取的字节数
    /* 重复调用fread并每次读取一定数量的值,文件指针会逐渐后移,直到触碰到文件末尾,循环跳出 */
    while ((ReadBytes = fread(Buffer, 1, sizeof(Buffer), File)) > 0) {
        httpd_resp_send_chunk(r, (const char*)Buffer, ReadBytes);
    } 
    httpd_resp_send_chunk(r, NULL, 0); //结束分块传输
    fclose(File);
}

同理,当post内容过多时,也可用该分块方式减轻服务端负担

示例

#define CHUNK_SIZE 512 //接收缓冲区大小
esp_err_t httpPostHandler(httpd_req_t *r) {
    uint8_t buffer[CHUNK_SIZE];
    int32_t remaining = r->content_len;

    while (remaining > 0) {
        int32_t to_read = (remaining > CHUNK_SIZE) ? CHUNK_SIZE : remaining; //尝试读取不超过缓冲区大小的最大值
        int32_t ret = httpd_req_recv(r, (char*)buffer, to_read);
        if (ret <= 0) {
            if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
                httpd_resp_send_408(r);
            }
            return ESP_FAIL;
        }
        remaining -= ret;
        /* 实现你的处理程序 */
    }
    httpd_resp_send_chunk(r, NULL, 0);  // 结束分块传输
    return ESP_OK;
}

注意事项

httpd_parse: parse_block: request URI/header too long 问题解决方案

部分安卓机自带Webview会出现此类问题,
提高 sdkconfig 中的 Max HTTP Request Header Length 的值

httpd_uri: httpd_register_uri_handler: no slots left for registering handler 问题解决方案

注册 httpd_register_uri_handler 数量过多导致
解决方案:提升max_uri_handlers数量

示例:

...
httpd_config_t Config = HTTPD_DEFAULT_CONFIG();
Config.max_uri_handlers = 10; //提升数量
...

附录

客户端网页解析发送数据及解析

示例:发送一个数据包(阻塞)

const text = ...
...
const response = await fetch('/text') { // 根据实际情况编写路径
  method: 'POST',
  body: text // 换成自己的包
}

接收一个数据包(阻塞)

const response = await fetch('/status'); // 根据实际情况编写路径

此作者没有提供个人介绍。
最后更新于 2025-10-23