库
esp_http_server.hesp_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'); // 根据实际情况编写路径
Comments NOTHING